Version 1.1.0 - Refactor + Intergration Backend

This commit is contained in:
2025-07-25 17:56:30 +02:00
parent a59d7a66db
commit 98cdae97c0
58 changed files with 244 additions and 70 deletions

943
src/server/Server.js Normal file
View File

@@ -0,0 +1,943 @@
const {LogType} = require('loguix')
const wlog = new LogType("Server")
const fs = require("fs")
const path = require("path")
const {Server} = require('socket.io')
const {createServer} = require('http')
const session = require("../server/auth/Session")
const users = require("../server/auth/User")
const players = require("../player/Player")
const {Player} = require("../player/Player")
const discordBot = require("../discord/Bot")
const discordAuth = require("../server/auth/DiscordAuth")
const {Report} = require("../discord/ReportSender")
const Finder = require("../player/Finder")
const {__glob} = require("../utils/GlobalVars")
const playlists = require("../playlists/PlaylistManager")
const history = require("../playlists/History")
const lyrics = require("../lyrics/Lyrics")
const mediaBase = require("../discord/MediaBase")
const googleApis = require("../playlists/Google/OAuth2")
const youtubeApi = require("../playlists/Google/YoutubeList")
const configuration = require("../utils/Database/Configuration")
const { List } = require('../player/List')
const { restart } = require('../utils/Maintenance')
const { isAudioFile } = require('../utils/AudioBufferCheck')
const { Song } = require('../player/Song')
const { getMediaInformationFromUrl } = require('../media/MediaInformation')
const allConnectedUsers = new Array()
const guildConnectedUsers = new Map()
const UsersBySocket = new Map()
//TODO: Refactor this file to implement the fact that server can be joined and leaved and all the events are now handled, so guildId is not required for every event
function init() {
wlog.step.init("server_init", "Initialisation du serveur Socket.IO")
const httpServer = createServer()
const io = new Server(httpServer, {
cors: {
origin: "*"
},
})
process.on("PLAYERS_UPDATE", () => {
if(io) {
// Get all players and send them to client subscribed to the guild
for(var guild of discordBot.getGuilds().keys()) {
const player = players.getPlayer(guild)
if(player) {
if(!player.isConnected()) continue;
io.to(player.guildId).emit("/PLAYER/UPDATE", player.getState())
wlog.log("Envoi de l'état du player de la guilde : " + player.guildId + " à tous les utilisateurs connectés")
}
}
}
})
process.on("USERS_UPDATE", () => {
if(io) {
updateGuildConnectedUsers()
// Get all players and send them to client subscribed to the guild
for(var guild of discordBot.getGuilds().keys()) {
if(guildConnectedUsers.has(guild)) {
io.to(guild).emit("/USERS/UPDATE", {"id": guild, "members": guildConnectedUsers.get(guild)} )
io.to("ADMIN").emit("ALL_USERS_UPDATE", allConnectedUsers)
wlog.log("Envoi de la liste des utilisateurs connectés (" + guildConnectedUsers.get(guild).length +") à la guilde : " + guild + " à tous les utilisateurs connectés")
}
}
io.sockets.emit("/USER/READY")
}
})
io.on("connection", async (socket) => {
var socketUser;
// Make sure Discord Bot is loaded and make an interruption until it is loaded
while(!await discordBot.isReady()) {
wlog.warn("Attente de traitement : "+ socket.id + " : Le bot Discord n'est pas encore chargé, attente de 0.5 seconde... (Avoid Rate Limit)")
await new Promise(resolve => setTimeout(resolve, 500))
}
wlog.log(`Connexion d'un client : ${socket.id}`)
socket.on("disconnect", () => {
handleDisconnect()
wlog.log("Déconnexion du client : " + socket.id)
})
socket.on("error", (error) => {
handleDisconnect()
wlog.error("Erreur sur le socket : " + socket.id + " - " + error)
})
if(socket.handshake.auth == undefined || socket.handshake.auth == {}) {
wlog.warn("Authentification manquant pour le client :" + socket.id)
sendSession()
return
}
var token = socket.handshake.auth.token
var sessionId = socket.handshake.auth.sessionId
var auth_code = socket.handshake.auth.auth_code
var inLogin = false
if(sessionId) {
if(!session.checkSession(sessionId)) {
wlog.warn("Session invalide pour le client : " + socket.id)
sendSession()
return;
} else {
if(auth_code) {
const discordUser = await discordAuth.getDiscordUser(sessionId, auth_code)
session.removeSession(sessionId)
if(discordUser == "GUILDS_ERROR" || discordUser == "USER_INFO_ERROR" || discordUser == "ACCESS_TOKEN_ERROR") {
wlog.warn("Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId)
socket.emit("AUTH_ERROR", discordUser)
socket.disconnect()
return
} else {
const loggedUser = await users.addUser(discordUser.auth, discordUser.identity, discordUser.guilds)
for(var guild of discordUser.guilds) {
if(guild.owner) {
users.setGuildOwner(loggedUser.identity.id, guild.id, true)
}
}
const newToken = await loggedUser.createToken()
socket.emit("NEW_TOKEN", newToken)
token = newToken
inLogin = true
wlog.log("Utilisateur Discord associé à la session : " + sessionId + " récupéré avec succès")
}
} else {
wlog.warn("Code d'authentification manquant pour le client :" + socket.id)
socket.emit("AUTH_ERROR", "Code manquant invalide")
socket.disconnect()
return
}
}
}
if(!token) {
wlog.warn("Token manquant pour le client :" + socket.id)
socket.emit("AUTH_ERROR", "Token invalide")
sendSession()
return
}
socketUser = users.getUserByToken(token)
if(!socketUser) {
wlog.warn("Token invalide pour le client :" + socket.id)
socket.emit("AUTH_ERROR", "Token invalide")
sendSession()
return
} else {
if(!socketUser.auth) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'a pas d'authentification Discord Valide")
socketUser.clearToken()
socket.emit("AUTH_ERROR", "L'authentification Discord de l'utilisateur n'est pas valide")
socket.disconnect()
return
}
if(!inLogin) {
if(socketUser.needUpdate()) {
if (!(await users.updateGuilds(socketUser.identity.id)) || !(await users.updateIdentity(socketUser.identity.id))) {
wlog.error("Erreur lors de la mise à jour des informations de l'utilisateur : " + socketUser.identity.id);
socket.emit("AUTH_ERROR", "Mise à jour des informations de l'utilisateur impossible");
wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
socket.disconnect();
return;
}
socketUser.justUpdated()
} else {
wlog.log("Pas de mise à jour des informations de l'utilisateur : " + socketUser.identity.id + " car l'utilisateur vient de se connecter")
}
} else {
wlog.log("L'utilisateur '" + socketUser.identity.username + "' s'est connecté via la session : " + sessionId)
}
}
socketUser = users.getUserByToken(token)
if(socketUser) {
if(allConnectedUsers.includes(socketUser.identity)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est déjà connecté sur un autre appareil")
return
} else {
allConnectedUsers.push(socketUser.identity)
addGuildConnectedUser(socketUser.identity, socketUser.guilds)
UsersBySocket.set(socketUser.identity.id, socket.id)
}
wlog.log("Utilisateur connecté : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
process.emit("USERS_UPDATE")
if(socketUser.isFullBanned()) {
wlog.warn("Utilisateur banni : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
socket.emit("AUTH_ERROR", "Vous êtes banni du serveur")
socket.disconnect()
}
if(socketUser.isAdmin()) {
socket.join("ADMIN")
wlog.log("Utilisateur admin identifié : " + socketUser.identity.username + " (" + socketUser.identity.id + ")")
}
IOAnswer("/USER/READY", true)
// USERS
// CHECKED : 24/04/2025
IORequest("/USER/INFO", () => {
var guildPresents = new Array();
var guildsOfBot = discordBot.getGuilds()
for(var guild of guildsOfBot) {
if(guild[1].members.includes(socketUser.identity.id)) {
const guildData = socketUser.guilds.find(g => g.id == guild[0])
guildData['members'] = new Array()
guildData.serverMember = guild[1].members.length
for(var user of guild[1].members) {
const userData = users.getUserById(user)
if(userData && userData.identity.id != socketUser.identity.id && allConnectedUsers.includes(userData.identity)) {
guildData.members.push({
id: userData.identity.id,
username: userData.identity.username,
avatar: userData.identity.avatar,
isAdmin: userData.isAdmin(),
isOwner: userData.isOwner(guild[0]),
isMod: userData.isMod(guild[0]),
})
}
}
// Send if the bot is connected to the guild
if(players.getPlayer(guild[0]) && players.getPlayer(guild[0]).isConnected()) {
guildData.connected = true
} else {
guildData.connected = false
}
guildPresents.push(guildData)
}
}
IOAnswer("/USER/INFO", {
identity: socketUser.identity,
guilds: guildPresents,
labels: socketUser.labels,
history: history.getPersonalHistory(socketUser.identity.id),
})
wlog.log("Envoi des informations Discord de '" + socketUser.identity.id + "' à '" + socket.id + "'" )
})
IORequest("/USER/HISTORY", () => {
IOAnswer("/USER/HISTORY", history.getPersonalHistory(socketUser.identity.id))
})
//CHECKED : 24/04/2025
IORequest("/USER/SIGNOUT", () => {
socketUser.removeToken(token)
IOAnswer("/USER/SIGNOUT", true)
socket.disconnect()
})
// CHECKED : 24/04/2025
IORequest("/USERS/LIST", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
if(!guildConnectedUsers.has(guildId)) return IOAnswer("/USERS/LIST", false)
IOAnswer("/USERS/LIST", guildConnectedUsers.get(guildId))
})
// PLAYERS
IORequest("/PLAYER/LYRICS", async (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
const player = await verifyPlayerAction(guildId)
if(!player) return IOAnswer("/PLAYER/LYRICS", false)
if(!player.queue?.current) {
wlog.warn("Le player de la guilde : " + guildId + " n'a pas de musique en cours")
IOAnswer("/PLAYER/LYRICS", false)
return
}
const song = player.queue.current
const lyricsData = await lyrics.getLyrics(song.title + " " + song.author)
console.log(lyricsData)
if(!lyricsData) {
wlog.warn("Aucune lyrics trouvée pour la musique : " + song.title + " de l'artiste : " + song.author)
IOAnswer("/PLAYER/LYRICS", false)
return
}
IOAnswer("/PLAYER/LYRICS", lyricsData)
})
//CHECKED : 03/05/2025
IORequest("/PLAYER/PREVIOUS/LIST", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
const list = new List(guildId)
IOAnswer("/PLAYER/PREVIOUS/LIST", list.getPrevious())
})
// ChECKED : 03/05/2025
IORequest("/PLAYER/JOIN", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
wlog.log("L'utilisateur '" + socketUser.identity.username + "' rejoint la liste d'écoute du player de la guilde : " + guildId)
// Make him to leave all the other rooms except the ADMIN room if he is admin
socket.rooms.forEach((room) => {
if(room != "ADMIN") {
socket.leave(room)
}
})
socket.join(guildId)
IOAnswer("/PLAYER/JOIN", true)
process.emit("PLAYERS_UPDATE")
})
// CHECKED : 03/05/2025
IORequest("/PLAYER/STATE", async (guildId) => {
const player = await verifyPlayerAction(guildId)
if(!player) return IOAnswer("/PLAYER/STATE", false)
IOAnswer("/PLAYER/STATE", await player.getState())
})
// CHECKED : 03/05/2025
IORequest("/PLAYER/PAUSE", (guildId) => {
handlePlayerAction(guildId, (player) => player.pause(), "/PLAYER/PAUSE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/BACKWARD", (guildId) => {
handlePlayerAction(guildId, (player) => player.previous(), "/PLAYER/BACKWARD");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/FORWARD", (guildId) => {
handlePlayerAction(guildId, (player) => player.skip(), "/PLAYER/FORWARD");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/LOOP", (guildId) => {
handlePlayerAction(guildId, (player) => player.setLoop(), "/PLAYER/LOOP");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/SHUFFLE", (guildId) => {
handlePlayerAction(guildId, (player) => player.setShuffle(), "/PLAYER/SHUFFLE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/DISCONNECT", (guildId) => {
handlePlayerAction(guildId, (player) => player.leave(), "/PLAYER/DISCONNECT");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/CHANNEL/CHANGE", (guildId) => {
handlePlayerAction(guildId, (player) => {
const channel = getUserChannel()
if(!channel) {
IOAnswer("/PLAYER/CHANNEL/CHANGE", false)
return
}
player.changeChannel(channel)
}, "/PLAYER/CHANNEL/CHANGE");
});
// CHECKED : 03/05/2025
IORequest("/PLAYER/SEEK", (data) => {
if(!data) return IOAnswer("/PLAYER/SEEK", false)
const {guildId, time} = data
if(!guildId) return IOAnswer("/PLAYER/SEEK", false)
if(!time) return IOAnswer("/PLAYER/SEEK", false)
handlePlayerAction(guildId, (player) => {
// Check if current is not null
if(player.queue.current == null) {
wlog.warn("Le player de la guilde : " + guildId + " n'a pas de musique en cours")
IOAnswer("/PLAYER/SEEK", false)
return
}
player.setDuration(time)
}, "/PLAYER/SEEK");
});
// CHECKED : 04/05/2025
IORequest("/QUEUE/PLAY", (data) => {
if(!data) return IOAnswer("/QUEUE/PLAY/NOW", false)
const {guildId, index, listType, now} = data
if(!index) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!guildId) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!listType) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/QUEUE/PLAY", false)
var song;
if(listType == "previous") {
const previous = player.queue.getPrevious()
song = previous[index]
} else if(listType == "next") {
const next = player.queue.getNext()
song = next[index]
}
if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(listType == "next") player.queue.removeNextByIndex(index)
if(now) {
player.play(song)
} else {
player.add(song)
}
history.addToPersonalHistory(socketUser.identity.id, song)
IOAnswer("/QUEUE/PLAY/NOW", true)
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/DELETE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/DELETE", false)
const {guildId, index} = data
if(!guildId) return IOAnswer("/QUEUE/NEXT/DELETE", false)
if(!index) return IOAnswer("/QUEUE/NEXT/DELETE", false)
handlePlayerAction(guildId, (player) => {
const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/DELETE", false);
player.queue.removeNextByIndex(index)
}, "/QUEUE/NEXT/DELETE")
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/DELETEALL", (guildId) => {
handlePlayerAction(guildId, (player) => player.queue.clearNext(), "/QUEUE/NEXT/DELETEALL")
})
// CHECKED : 04/05/2025
IORequest("/QUEUE/NEXT/MOVE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/MOVE", false)
const {guildId, index, newIndex} = data
if(!guildId) return IOAnswer("/QUEUE/NEXT/MOVE", false)
if(!index) return IOAnswer("/QUEUE/NEXT/MOVE", false)
if(!newIndex) return IOAnswer("/QUEUE/NEXT/MOVE", false)
handlePlayerAction(guildId, (player) => {
const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/MOVE", false);
player.queue.moveNext(index, newIndex)
}, "/QUEUE/NEXT/MOVE")
})
// SEARCH
// CHECKED : 24/04/2025
IORequest("/SEARCH", async (query) => {
IOAnswer("/SEARCH", await Finder.search(query, true))
})
// CHECKED : 03/05/2025
IORequest("/SEARCH/PLAY", async (data) => {
if(!data) return IOAnswer("/SEARCH/PLAY", false)
var {guildId, song, now} = data
if(!song) return IOAnswer("/SEARCH/PLAY", false)
if(typeof song == "string") {
song = JSON.parse(song)
}
if(!guildId) return IOAnswer("/SEARCH/PLAY", false)
if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/SEARCH/PLAY", false)
if(now) {
player.play(song)
} else {
player.add(song)
}
history.addToPersonalHistory(socketUser.identity.id, song)
IOAnswer("/SEARCH/PLAY", true)
})
// CHECKED : 05/05/2025
IORequest("/SEARCH/PLAYLIST", async (data) => {
if(!data) return IOAnswer("/SEARCH/PLAYLIST", false)
const {url, now, guildId} = data
if(!url) return IOAnswer("/SEARCH/PLAYLIST", false)
if(!guildId) return IOAnswer("/SEARCH/PLAYLIST", false)
const playlist = await Finder.search(url, true, "PLAYLIST")
if(!playlist) return IOAnswer("/SEARCH/PLAYLIST", false)
const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/SEARCH/PLAYLIST", false)
player.readPlaylist(playlist, now)
IOAnswer("/SEARCH/PLAYLIST", true)
})
IORequest("/SEARCH/LYRICS", async (name) => {
if(!name) return IOAnswer("/SEARCH/LYRICS", false)
const lyricsData = await lyrics.getLyrics(name)
if(!lyricsData) return IOAnswer("/SEARCH/LYRICS", false)
IOAnswer("/SEARCH/LYRICS", lyricsData)
})
// UPLOAD
// CHECKED : 29/05/2025
IORequest("/UPLOAD/FILE", async (data) => {
if(!data) return IOAnswer("/UPLOAD/FILE", false)
if(!data.name) return IOAnswer("/UPLOAD/FILE", false)
const file = data.file
// Check wav or mp3
if(isAudioFile(file) == false) {
wlog.warn("Le fichier envoyé n'est pas un fichier audio valide (MP3/WAV)")
return IOAnswer("/UPLOAD/FILE", false)
}
const url = await mediaBase.postMedia(data)
if(!url) return IOAnswer("/UPLOAD/FILE", false)
IOAnswer("/UPLOAD/FILE", {"url": url, "name": data.name})
})
// CHECKED : 29/05/2025
IORequest("/UPLOAD/FILE/GET_SONG", async (data) => {
if(!data) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
const {name, url} = data
if(!url) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
if(!name) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
const song = new Song()
if(!song) return IOAnswer("/UPLOAD/FILE/GET_SONG", false)
await getMediaInformationFromUrl(song, url)
song.type = "attachment"
song.author = socketUser.identity.username
song.authorId = socketUser.identity.id
song.title = name
song.url = url
IOAnswer("/UPLOAD/FILE/GET_SONG", song)
})
// GOOGLE API
IORequest("/GOOGLE/AUTH", () => {
IOAnswer("/GOOGLE/AUTH", googleApis.createAuthUrl(socketUser.identity.id))
})
IORequest("/GOOGLE/YOUTUBE/ADD_PLAYLIST", async (code) => {
if(!code) {
IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false)
}
const token = await googleApis.getAuthorization(socketUser.identity.id, code)
if(!token) {
IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", false)
return
}
playlists.processYoutubeData(socketUser.identity.id, await youtubeApi.getYoutubePlaylists(socketUser.identity.id))
IOAnswer("/GOOGLE/YOUTUBE/ADD_PLAYLIST", true)
})
// PLAYLISTS
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/CREATE", async (data) => {
if(!data) return IOAnswer("/PLAYLISTS/CREATE", false)
const {name, url} = data
if(!name) return IOAnswer("/PLAYLISTS/CREATE", false)
const playlist = await playlists.addPlaylist(socketUser.identity.id, name, url)
if(!playlist) return IOAnswer("/PLAYLISTS/CREATE", false)
IOAnswer("/PLAYLISTS/CREATE", true)
})
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/DELETE", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/DELETE", false)
const {name} = data
if(!name) return IOAnswer("/PLAYLISTS/DELETE", false)
playlists.removePlaylist(socketUser.identity.id, name)
IOAnswer("/PLAYLISTS/DELETE", true)
})
// CHECKED : 24/04/2025
IORequest("/PLAYLISTS/LIST", () => {
const playlist = playlists.getPlaylistsOfUser(socketUser.identity.id)
IOAnswer("/PLAYLISTS/LIST", playlist)
})
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/SEND", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/SEND", false)
const {name, toId} = data
if(!name || !toId) return IOAnswer("/PLAYLISTS/SEND", false)
// Check if toId is in the same guilds as the user
// Check if the toId exists and have a playlist with the same name
const toUser = users.getUserById(toId)
if(!toUser) return IOAnswer("/PLAYLISTS/SEND", false)
const toPlaylists = playlists.getPlaylistsOfUser(toUser.identity.id)
const fromPlaylist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!fromPlaylist) return IOAnswer("/PLAYLISTS/SEND", false)
if(toPlaylists.find(p => p.name == name)) return IOAnswer("/PLAYLISTS/SEND", false)
playlists.copyPlaylist(socketUser.identity.id, toUser.identity.id, name)
IOAnswer("/PLAYLISTS/SEND", true)
})
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/RENAME", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/RENAME", false)
const {name, newName} = data
if(!name || !newName) return IOAnswer("/PLAYLISTS/RENAME", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/RENAME", false)
playlists.renamePlaylist(socketUser.identity.id, name, newName)
IOAnswer("/PLAYLISTS/RENAME", true)
})
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/ADD_SONG", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
const {name, song} = data
if(!name || !song) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
playlists.addSong(socketUser.identity.id, name, song)
IOAnswer("/PLAYLISTS/ADD_SONG", true)
})
// CHECKED : 30/04/2025
IORequest("/PLAYLISTS/REMOVE_SONG", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
const {name, songId} = data
if(!name || !songId) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
playlists.removeSong(socketUser.identity.id, name, songId)
IOAnswer("/PLAYLISTS/REMOVE_SONG", true)
})
// CHECKED : 05/05/2025
IORequest("/PLAYLISTS/PLAY", async (data) => {
if(!data) return IOAnswer("/PLAYLISTS/PLAY", false)
const {name, guildId, now} = data
if(!name || !guildId) return IOAnswer("/PLAYLISTS/PLAY", false)
if(!checkUserGuild(socketUser, guildId)) return IOAnswer("/PLAYLISTS/PLAY", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/PLAY", false)
const player = new Player(guildId)
if(!await connectToPlayer(guildId, player)) return IOAnswer("/PLAYLISTS/PLAY", false)
player.readPlaylist(playlist, now)
IOAnswer("/PLAYLISTS/PLAY", true)
})
// ADMIN
if(socketUser.isAdmin()) {
// CHECKED : 24/04/2025
IORequest("/ADMIN/LOGS", () => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/LOGS", false)
const logs_data = new Array()
const logs_folder = fs.readdirSync(__glob.LOGS)
for(var log of logs_folder) {
logs_data.push({"name":log, "value": fs.readFileSync(__glob.LOGS + path.sep + log).toString()})
}
IOAnswer("/ADMIN/LOGS", logs_data)
})
// CHECKED : 24/04/2025
IORequest("/ADMIN/MAINTENANCE/RESTART", (reason) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false)
if(!reason) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false)
restart(reason)
})
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/SWITCH_ADMIN", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
users.setAdmin(userId)
IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", true)
})
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/FULL_BAN", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
users.setFullBan(userId)
IOAnswer("/ADMIN/USERS/FULL_BAN", true)
})
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/DELETE", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false)
users.removeUser(userId)
const userSocket = UsersBySocket.get(userId)
if(userSocket) {
const socket = io.sockets.sockets.get(userSocket)
if(socket) {
socket.emit("AUTH_ERROR", "Votre compte a été supprimé")
socket.disconnect()
}
}
IOAnswer("/ADMIN/USERS/DELETE", true)
})
// CHECKED : 24/04/2025
IORequest("/ADMIN/PLAYER/GETALLSTATE", async () => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/PLAYER/GETTALLSTATE", false)
const allPlayers = players.getAllPlayers()
const states = new Array()
for(var player in allPlayers) {
await states.push(await player.getState())
}
IOAnswer("/ADMIN/PLAYER/GETALLSTATE", states)
})
}
// CHECKED : 24/04/2025
IORequest("/OWNER/USERS/SWITCH_MOD", (data) => {
if(!data["userId"] || !data["guildId"]) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
const userId = data["userId"]
const guildId = data["guildId"]
if(socketUser.identity.id == userId) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
if(!socketUser.isOwner(guildId)) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
users.setGuildMod(userId, guildId)
IOAnswer("/OWNER/USERS/SWITCH_MOD", true)
})
// CHECKED : 24/04/2025
IORequest("/MOD/USERS/BAN", (data) => {
if(!data["userId"] || !data["guildId"]) return IOAnswer("/MOD/USERS/BAN", false)
const userId = data["userId"]
const guildId = data["guildId"]
if(socketUser.identity.id == userId) return IOAnswer("/MOD/USERS/BAN", false)
if(!socketUser.isMod(guildId)) return IOAnswer("/MOD/USERS/BAN", false)
users.setGuildBan(userId, guildId)
IOAnswer("/MOD/USERS/BAN", true)
})
// UTILS
// CHECKED : 24/04/2025
IORequest("/REPORT", (data) => {
if(data.length < 2) return IOAnswer("/REPORT", false)
if(!data["level"] || !data["desc"]) return IOAnswer("/REPORT", false)
const report = new Report(socketUser.identity.username, data["level"], data["desc"]).send()
IOAnswer("/REPORT", true)
})
// Functions
function getUserChannel() {
const membersVoices = discordBot.getMembersVoices()
const member = membersVoices.get(socketUser.identity.id)
if(member) {
const channelId = member.channelId
const guildId = member.guildId
const channel = discordBot.getChannel(guildId, channelId)
if(!channel) {
wlog.warn("Le channel vocal n'existe pas : " + channelId)
return null
}
return channel
} else {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas dans un channel vocal")
return null
}
}
/**
* @param {Player} player
*/
function connectToPlayer(guildId, player) {
if(!checkUserGuild(socketUser, guildId)) return false
if(player.isConnected()) true
const channel = getUserChannel()
if(!channel) return false
player.join(channel)
return true
}
async function verifyPlayerAction(guildId) {
if (!checkUserGuild(socketUser, guildId)) return null;
const player = players.getPlayer(guildId);
if (player) {
return player;
} else {
wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`);
return null;
}
}
function checkUserGuild(socketUser, guildId) {
// Check if the guildId is referenced in the bot guilds
if(!discordBot.getGuilds().has(guildId)) {
wlog.warn("La guilde : " + guildId + " n'est pas référencée dans le bot")
return false
}
if(socketUser.isBanned(guildId)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est banni de la guilde : " + guildId)
return false
}
if(!socketUser.guilds.find(g => g.id == guildId)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas membre de la guilde : " + guildId)
// Si user admin, override
if(!socketUser.isAdmin()) {
return false
}
wlog.log("L'utilisateur '" + socketUser.identity.username + "' est admin donc à le droit d'accéder à la guilde : " + guildId)
}
return true
}
/**
* @param {function(Player)} action - The action to perform on the player.
*/
async function handlePlayerAction(guildId, action, actionName) {
if (!checkUserGuild(socketUser, guildId)) return;
const player = players.getPlayer(guildId);
if (player) {
await action(player);
wlog.log(`L'utilisateur '${socketUser.identity.username}' effectue l'action '${actionName}' sur le player de la guilde : ${guildId}`);
IOAnswer(actionName, true);
} else {
wlog.warn(`Le player de la guilde : ${guildId} n'existe pas`);
IOAnswer(actionName, false);
}
}
}
function handleDisconnect() {
if(socketUser) {
wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
allConnectedUsers.splice(allConnectedUsers.indexOf(socketUser.identity), 1)
removeGuildConnectedUser(socketUser.identity)
process.emit("USERS_UPDATE")
if(socketUser.isAdmin()) {
socket.leave("ADMIN")
}
UsersBySocket.delete(socketUser.identity.id)
}
}
function sendSession() {
const newSession = session.addSession(socket.id)
socket.emit("NEW_SESSION", newSession)
wlog.log("Envoi d'une nouvelle session : '" + newSession + "' au client : " + socket.id)
socket.disconnect()
}
function IORequest(RequestName, RequestCallback) {
socket.on(RequestName, (value) => {
wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + RequestName + " - [RECIEVED]")
RequestCallback(value)
})
}
function IOAnswer(AnswerName, AnswerValue) {
wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + AnswerName + " - [ANSWERED]")
socket.emit(AnswerName, AnswerValue)
}
})
httpServer.listen(configuration.getPort(), () => {
wlog.log(`Le serveur écoute sur le port ${configuration.getPort()}`)
wlog.step.end("server_init")
})
function addGuildConnectedUser(user, guilds) {
// Check if guilds is iterable
if(!guilds || !guilds[Symbol.iterator]) {
wlog.warn("Les guilds ne sont pas itérables")
return
}
for(var guild of guilds) {
if(!guildConnectedUsers.has(guild)) {
guildConnectedUsers.set(guild.id, new Array())
}
guildConnectedUsers.get(guild.id).push(user)
}
}
function removeGuildConnectedUser(user) {
for(var guild of guildConnectedUsers.keys()) {
const users = guildConnectedUsers.get(guild)
if(users.includes(user)) {
users.splice(users.indexOf(user), 1)
if(users.length == 0) {
guildConnectedUsers.delete(guild)
}
}
}
}
function updateGuildConnectedUsers() {
guildConnectedUsers.clear()
// Get from discordBot
const guilds = discordBot.getGuilds()
for(var guild of guilds) {
const members = discordBot.getGuildMembers(guild[0])
if(!members) continue
for(var member of members) {
const user = users.getUserById(member)
if(user && allConnectedUsers.includes(user.identity)) {
if(!guildConnectedUsers.has(guild[0])) {
guildConnectedUsers.set(guild[0], new Array())
}
guildConnectedUsers.get(guild[0]).push(user)
}
}
}
}
}
module.exports = {init}

View File

@@ -0,0 +1,146 @@
const { LogType } = require('loguix');
const dlog = new LogType("DiscordAuth");
const { getWebsiteLink, getClientSecret } = require('../../utils/Database/Configuration');
async function getDiscordUser(sessionId, auth_code) {
return new Promise((resolve, reject) => {
const discordBot = require("../../discord/Bot")
const discordBotClient = discordBot.getClient()
dlog.step.init("discord_auth_" + sessionId, "Authentification Discord de la session :" + sessionId);
dlog.log("Récupération de l'autorisation de récupération des informations de l'utilisateur Discord associé à la session : " + sessionId);
const params = new URLSearchParams();
params.append("client_id", discordBotClient.user.id);
params.append("client_secret", getClientSecret());
params.append("grant_type", "authorization_code");
params.append("code", auth_code);
params.append("redirect_uri", getWebsiteLink() + "/redirect");
params.append("scope", "identify guilds");
fetch("https://discord.com/api/oauth2/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
}).then(accessTokenResp => accessTokenResp.json()).then(accessToken => {
if (accessToken.error) {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération du token d'accès Discord associé à la session : " + sessionId + " : " + accessToken.error + " : " + accessToken.error_description);
resolve("ACCESS_TOKEN_ERROR");
return;
}
dlog.log("Récupération réussi du token d'accès Discord associé à la session : " + sessionId);
fetch("https://discord.com/api/users/@me", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(userResp => userResp.json()).then(user => {
dlog.log("Récupération réussi des informations de l'utilisateur Discord associé à la session : " + sessionId + " avec le nom d'utilisateur : " + user.username + " (" + user.id + ")");
// Get the guilds of the user
fetch("https://discord.com/api/users/@me/guilds", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(guildsResp => guildsResp.json()).then(guilds => {
dlog.log("Récupération réussi des guildes de l'utilisateur Discord associé à la session : " + sessionId + " avec le nom d'utilisateur : " + user.username + " (" + user.id + ")");
dlog.step.end("discord_auth_" + sessionId)
const userData = {
auth: accessToken,
identity: user,
guilds: guilds,
}
resolve(userData);
}).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des guildes de l'utilisateur Discord" + " avec le nom d'utilisateur : " + user.username + " (" + user.id + ")" + " associé à la session : " + sessionId + " : " + err);
resolve("GUILDS_ERROR");
});
}).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId + " : " + err);
resolve( "USER_INFO_ERROR");
})
}).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération du token d'accès Discord associé à la session : " + sessionId + " : " + err);
resolve("ACCESS_TOKEN_ERROR");
})
})
}
function refreshToken(refresh_token) {
return new Promise((resolve, reject) => {
const discordBot = require("../../discord/Bot")
const params = new URLSearchParams();
params.append("client_id", discordBot.getClient().user.id);
params.append("client_secret", getClientSecret());
params.append("grant_type", "refresh_token");
params.append("refresh_token", refresh_token);
params.append("scope", "identify guilds");
fetch("https://discord.com/api/oauth2/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
}).then(accessTokenResp => accessTokenResp.json()).then(accessToken => {
if (accessToken.error) {
dlog.error("Erreur lors de la récupération du token d'accès Discord : " + accessToken.error + " : " + accessToken.error_description);
resolve(null);
return;
}
resolve(accessToken);
}).catch(err => {
dlog.error("Erreur lors de la récupération du token d'accès Discord : " + err);
resolve(null);
})
})
}
function getUserGuilds(accessToken) {
return new Promise((resolve, reject) => {
fetch("https://discord.com/api/users/@me/guilds", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(guildsResp => guildsResp.json()).then(guilds => {
if (guilds.error) {
dlog.error("Erreur lors de la récupération des guildes de l'utilisateur Discord : " + guilds.error + " : " + guilds.error_description);
dlog.log(accessToken.token_type + " " + accessToken.access_token )
resolve(null);
return;
}
resolve(guilds);
}).catch(err => {
dlog.error( "Erreur lors de la récupération des guildes de l'utilisateur Discord : " + err);
resolve(null);
})
})
}
function getUserIdentity(accessToken) {
return new Promise((resolve, reject) => {
fetch("https://discord.com/api/users/@me", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(userResp => userResp.json()).then(user => {
if (user.error) {
dlog.error("Erreur lors de la récupération des informations de l'utilisateur Discord : " + user.error + " : " + user.error_description);
resolve(null);
return;
}
resolve(user);
}).catch(err => {
dlog.error("Erreur lors de la récupération des informations de l'utilisateur Discord : " + err);
resolve(null);
})
})
}
module.exports = {getDiscordUser, refreshToken, getUserGuilds, getUserIdentity}

View File

@@ -0,0 +1,33 @@
const { LogType } = require('loguix');
const { generateSessionId } = require('../../utils/TokenManager');
const clog = new LogType("Session");
const sessions = new Array();
function checkSession(sessionId) {
return sessions.includes(sessionId);
}
function addSession() {
const sessionId = generateSessionId();
if (checkSession(sessionId)) {
clog.warn(`Session ${sessionId} non trouvée dans la liste des sessions.`);
return addSession(); // Recursively generate a new session ID if it already exists
}
sessions.push(sessionId);
clog.log(`Nouvelle session ${sessionId} ajoutée.`);
return sessionId;
}
function removeSession(sessionId) {
const index = sessions.indexOf(sessionId);
if (index > -1) {
sessions.splice(index, 1);
clog.log(`Suppression de la session ${sessionId}.`);
} else {
clog.warn(`Session ${sessionId} non trouvée dans la liste des sessions.`);
}
}
module.exports = {checkSession, addSession, removeSession};

570
src/server/auth/User.js Normal file
View File

@@ -0,0 +1,570 @@
const { Database } = require('../../utils/Database/Database');
const { __glob } = require('../../utils/GlobalVars');
const { generateToken } = require('../../utils/TokenManager');
const { LogType } = require('loguix');
const clog = new LogType("User");
const discordAuth = require('./DiscordAuth');
const e = require('cors');
const UserDB = new Database("Users", __glob.USERFILE, []);
var userList = new Array();
class User {
auth;
identity;
tokens;
labels;
guilds;
constructor(auth, identity, tokens, labels, guilds) {
this.auth = auth;
this.identity = identity;
this.tokens = tokens;
this.labels = labels;
this.guilds = guilds;
}
setAdmin() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
if (userInUserList.labels.includes("ADMIN")) {
userInUserList.labels.splice(userInUserList.labels.indexOf("ADMIN"), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus admin.`);
} else {
userInUserList.labels.push("ADMIN");
clog.log(`L'utilisateur ${this.identity.username} est maintenant admin.`);
}
saveUsers()
}
setBan(guildId) {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
const banLabel = `BAN_${guildId}`;
if (userInUserList.labels.includes(banLabel)) {
userInUserList.labels.splice(userInUserList.labels.indexOf(banLabel), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus banni du serveur ${guildId}.`);
} else {
userInUserList.labels.push(banLabel);
clog.log(`L'utilisateur ${this.identity.username} est maintenant banni du serveur ${guildId}.`);
}
saveUsers()
}
createToken() {
const token = generateToken(this.identity.id);
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.tokens.push(token);
saveUsers();
clog.log(`Token créé pour l'utilisateur ${this.identity.username}.`);
return token;
}
removeToken(token) {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
const index = userInUserList.tokens.indexOf(token);
if (index > -1) {
userInUserList.tokens.splice(index, 1);
saveUsers();
clog.log(`Token supprimé pour l'utilisateur ${this.identity.username}.`);
} else {
clog.warn(`Token non trouvé pour l'utilisateur ${this.identity.username}.`);
}
}
clearToken() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.tokens = [];
saveUsers();
clog.log(`Tous les tokens supprimés pour l'utilisateur ${this.identity.username}.`);
return userInUserList.tokens;
}
clearAuth() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.auth = null;
saveUsers();
clog.log(`Authentification supprimée pour l'utilisateur ${this.identity.username}.`);
}
destroyAuth() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.auth = null;
userInUserList.tokens = [];
saveUsers();
clog.log(`Authentification et tokens supprimés pour l'utilisateur ${this.identity.username}.`);
}
setFullBan() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
if (userInUserList.labels.find(label => label == "BAN")) {
userInUserList.labels.splice(userInUserList.labels.indexOf("BAN"), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus banni.`);
} else {
userInUserList.labels.push("BAN");
clog.log(`L'utilisateur ${this.identity.username} est maintenant banni.`);
}
saveUsers()
}
isBanned(guildId) {
const banLabel = `BAN_${guildId}`;
return this.labels.includes(banLabel);
}
isFullBanned() {
return this.labels.includes("BAN");
}
isAdmin() {
return this.labels.includes("ADMIN");
}
isMod(guildId) {
if(this.isOwner(guildId)) return true;
const modLabel = `MOD_${guildId}`;
return this.labels.includes(modLabel);
}
isOwner(guildId) {
const ownerLabel = `OWNER_${guildId}`;
if(this.isAdmin()) return true;
return this.labels.includes(ownerLabel);
}
justUpdated() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return false;
}
userInUserList.labels = userInUserList.labels.filter(label => !label.startsWith("UPDATED["));
userInUserList.labels.push("UPDATED[" + new Date().toISOString() + "]");
saveUsers();
}
needUpdate() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return false;
}
const lastUpdate = userInUserList.labels.find(label => label.startsWith("UPDATED["));
if (lastUpdate) {
const date = new Date(lastUpdate.replace("UPDATED[", "").replace("]", ""));
const now = new Date();
const diff = now - date;
// Check for 30 seconds
clog.log(`Dernière mise à jour de l'utilisateur ${this.identity.username} : ${date.toISOString()} (${diff} ms) - Besoin de mise à jour : ${diff > 30000}`);
// If the difference is greater than 30 seconds, we need to update
return diff > 30000; // 30 seconds
}
clog.log(`Aucune mise à jour n'a été effectuée pour l'utilisateur ${this.identity.username}.`);
return true;
}
}
//REFRESH USER
async function refreshAllUserInformation() {
await loadUsers();
clog.log("Récupération des informations de tous les utilisateurs...");
for (const user of userList) {
await updateCredientials(user.identity.id);
}
saveUsers();
}
async function updateCredientials(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Mise à jour des informations d'authentification Discord de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
// Check if the token is expired
const auth = await discordAuth.refreshToken(user.auth.refresh_token);
if (auth) {
// Check Rate limit by checking if auth.message exists
if(typeof auth.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${auth.message}`);
return null;
}
user.auth = auth;
clog.log(`Mise à jour réussie des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id})`);
} else {
clog.warn(`Erreur lors de la mise à jour des informations d'authentification de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
}
}
else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
saveUsers();
return user.auth;
}
async function updateGuilds(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const guilds = await discordAuth.getUserGuilds(user.auth);
if(guilds) {
if(typeof guilds.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${guilds.message}`);
return null;
}
user.guilds = guilds;
clog.log(`Mise à jour réussie des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.guilds = user.guilds;
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
saveUsers();
return user.guilds;
}
async function updateIdentity(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const identity = await discordAuth.getUserIdentity(user.auth);
if(identity) {
// Check Rate limit by checking if identity.message exists
if(typeof identity.message !== "undefined") {
clog.warn(`Erreur lors de la mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id}) : ${identity.message}`);
return null;
}
user.identity = identity;
clog.log(`Mise à jour réussie de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.identity = user.identity;
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
return null;
}
saveUsers();
return user.identity;
}
// EDIT USER
/**
*
* @param {*} auth
* @param {*} identity
* @param {*} guilds
* @returns {User} user
*/
async function addUser(auth, identity, guilds) {
// Check if the user already exists
const existingUser = userList.find(user => user.identity.id === identity.id);
if (existingUser) {
clog.warn(`L'utilisateur ${identity.username} existe déjà.`);
// Update the existing user with new information
existingUser.auth = auth;
existingUser.identity = identity;
existingUser.guilds = guilds;
existingUser.tokens = existingUser.tokens || []; // Ensure tokens array exists
existingUser.labels = existingUser.labels || []; // Ensure labels array exists
saveUsers();
clog.log(`Utilisateur ${identity.username} mis à jour.`);
return existingUser;
}
const newUser = new User(auth, identity, [], [], guilds);
userList.push(newUser);
await saveUsers();
return newUser;
}
function removeUser(id) {
const index = userList.findIndex(user => user.identity.id === id);
if (index > -1) {
userList.splice(index, 1);
saveUsers();
clog.log(`Utilisateur ${id} supprimé.`);
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
function removeToken(token) {
const user = getUserByToken(token);
if (user) {
const index = user.tokens.indexOf(token);
if (index > -1) {
user.tokens.splice(index, 1);
saveUsers();
clog.log(`Token ${token} supprimé pour l'utilisateur ${user.identity.username}.`);
} else {
clog.warn(`Token ${token} non trouvé pour l'utilisateur ${user.identity.username}.`);
}
} else {
clog.warn(`Utilisateur avec le token "${token}" non trouvé.`);
}
return user;
}
function addToken(id) {
const user = getUserById(id);
if (user) {
const token = generateToken();
user.tokens.push(token);
saveUsers();
clog.log(`Token "${token}" ajouté pour l'utilisateur ${user.identity.username}.`);
return token;
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
}
// GET
/**
* @param {string} id
* @returns {User} user
*/
function getUserById(id) {
return userList.find(user => user.identity.id === id) || null;
}
/**
*
* @param {string} token
* @returns {User} user
*/
function getUserByToken(token) {
return userList.find(user => user.tokens.includes(token)) || null;
}
function getUsers() {
return userList;
}
function getSimpleUsers() {
return userList.map(user => {
return {
identity: user.identity,
labels: user.labels,
guilds: user.guilds
};
});
}
function getSimpleUser(id) {
const user = getUserById(id);
if(user) {
return {
identity: user.identity,
labels: user.labels,
guilds: user.guilds
};
} else {
return null;
}
}
// SET LABELS
function setAdmin(id) {
const user = getUserById(id);
if (user) {
user.setAdmin();
saveUsers();
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
function setGuildMod(id, guildId) {
const user = getUserById(id);
if (user) {
const modLabel = `MOD_${guildId}`;
if (user.labels.includes(modLabel)) {
user.labels.splice(user.labels.indexOf(modLabel), 1);
clog.log(`L'utilisateur ${user.identity.username} n'est plus modérateur du serveur ${guildId}.`);
} else {
user.labels.push(modLabel);
clog.log(`L'utilisateur ${user.identity.username} est maintenant modérateur du serveur ${guildId}.`);
}
saveUsers();
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
function setGuildBan(id, guildId) {
const user = getUserById(id);
if (user) {
if(user.isAdmin()) {
clog.warn(`L'utilisateur ${user.identity.username} est admin, il ne peut pas être banni.`);
return;
}
user.setBan(guildId);
saveUsers();
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
function setFullBan(id) {
const user = getUserById(id);
if (user) {
if(user.isAdmin()) {
clog.warn(`L'utilisateur ${user.identity.username} est admin, il ne peut pas être banni.`);
return;
}
user.setFullBan();
saveUsers();
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
function setGuildOwner(id, guildId, force) {
const user = getUserById(id);
if (user) {
const ownerLabel = `OWNER_${guildId}`;
if (user.labels.includes(ownerLabel) && !force) {
user.labels.splice(user.labels.indexOf(ownerLabel), 1);
clog.log(`L'utilisateur ${user.identity.username} n'est plus propriétaire du serveur ${guildId}.`);
} else {
if(force && user.labels.includes(ownerLabel)) {
return;
}
user.labels.push(ownerLabel);
clog.log(`L'utilisateur ${user.identity.username} est maintenant propriétaire du serveur ${guildId}.`);
}
saveUsers();
} else {
clog.warn(`Utilisateur ${id} non trouvé.`);
}
}
// USERS DB
function loadUsers() {
UserDB.load()
userList = new Array();
for (const user of UserDB.getData()) {
userList.push(new User(user.auth, user.identity, user.tokens, user.labels, user.guilds));
}
clog.log(`Chargement de ${userList.length} utilisateurs.`);
return userList;
}
function saveUsers() {
UserDB.data = userList.map(user => {
return {
auth: user.auth,
identity: user.identity,
tokens: user.tokens,
labels: user.labels,
guilds: user.guilds
};
});
UserDB.save()
clog.log(`Sauvegarde de ${userList.length} utilisateurs.`);
return loadUsers();
}
function clearNeedUpdateForUsers() {
userList.forEach(user => {
user.labels = user.labels.filter(label => !label.startsWith("UPDATED["));
});
saveUsers();
clog.log("Nettoyage des mises à jour nécessaires pour tous les utilisateurs.");
}
module.exports = {User}
module.exports = {
addUser,
setGuildOwner,
setFullBan,
removeUser,
getUserByToken,
getUserById,
getUsers,
setAdmin,
setGuildMod,
setGuildBan,
addToken,
removeToken,
getSimpleUsers,
getSimpleUser,
updateCredientials,
refreshAllUserInformation,
updateGuilds,
updateIdentity,
clearNeedUpdateForUsers
};