From c50488a740d7b620dfec038cf19071c24ecae1f6 Mon Sep 17 00:00:00 2001 From: Burlone <108557545+burlone0@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:43:45 +0100 Subject: [PATCH] Added /createhostaccount, Fixed too much stuff Co-Authored-By: Waslyl <129678963+waslyl@users.noreply.github.com> --- CloudStorage/DefaultGame.ini | 2 + Config/DefaultProfiles/athena.json | 124 +++++++++++ DiscordBot/commands/Admin/additem.js | 210 ++++++++++++------ DiscordBot/commands/Admin/addvbucks.js | 133 ++++++++--- .../commands/Admin/createhostaccount.js | 78 +++++++ DiscordBot/commands/Admin/delete.js | 12 +- DiscordBot/commands/Admin/deletediscord.js | 12 +- DiscordBot/commands/Admin/removeitem.js | 2 +- DiscordBot/commands/User/change-email.js | 28 ++- DiscordBot/commands/User/change-password.js | 28 ++- DiscordBot/commands/User/change-username.js | 27 ++- README.md | 1 + model/user.js | 2 +- package-lock.json | 4 +- package.json | 2 +- routes/mcp.js | 2 +- structs/functions.js | 24 +- 17 files changed, 557 insertions(+), 134 deletions(-) create mode 100644 DiscordBot/commands/Admin/createhostaccount.js diff --git a/CloudStorage/DefaultGame.ini b/CloudStorage/DefaultGame.ini index d4f2cb2..974f4bd 100644 --- a/CloudStorage/DefaultGame.ini +++ b/CloudStorage/DefaultGame.ini @@ -22,6 +22,8 @@ bEnableCreativeMode=false ; Change "false" to "true" if u want Enable Creative s ;bClientSideEditPrediction=false [/Script/FortniteGame.FortTextHotfixConfig] ++TextReplacements=(Category=Game, bIsMinimalPatch=True, Namespace="", Key="9F28701D47C7B91B048FEBA378ADDEAE", NativeString="Epic Games", LocalizedStrings=(("en","Reload Backend"))) + +TextReplacements=(Category=Game, bIsMinimalPatch=True, Namespace="LoadingScreen", Key="Connecting", NativeString="CONNECTING", LocalizedStrings=(("en","CONNECTING TO Reload"))) +TextReplacements=(Category=Game, bIsMinimalPatch=True, Namespace="FortLoginStatus", Key="LoggingIn", NativeString="Logging In...", LocalizedStrings=(("ar","تسجيل الدخول إلى Reload..."),("en","Logging Into Reload..."),("de","Bei Reload anmelden..."),("es","Iniciando sesión en Reload..."),("es-419","Iniciando sesión en Reload..."),("fr","Connexion à Reload..."),("it","Accesso a Reload..."),("ja","Reload にログインしています..."),("ko","Reload에 로그인하는 중..."),("pl","Logowanie do Reload..."),("pt-BR","Iniciando sesión en Reload..."),("ru","Вход в Reload..."),("tr","Reload'ye Giriş Yapılıyor..."),("zh-CN","Ngena ngemvume ku-Reload..."),("zh-Hant","Ngena ngemvume ku-Reload..."))) +TextReplacements=(Category=Game, bIsMinimalPatch=True, Namespace="OnlineAccount", Key="DoQosPingTests", NativeString="Checking connection to datacenters...", LocalizedStrings=(("ar","جارٍ التحقق من الاتصال بـ Reload..."),("en","Checking connection to Reload..."),("de","Verbindung zu Reload wird überprüft..."),("es","Comprobando conexión a Reload..."),("es-419","Comprobando conexión a Reload..."),("fr","Vérification de la connexion à Reload..."),("it","Controllo della connessione a Reload..."),("ja","Reload への接続を確認しています..."),("ko","Reload 연결을 확인하는 중..."),("pl","Sprawdzam połączenie z Reload..."),("pt-BR","Comprobando conexión a Reload..."),("ru","Проверка подключения к Reload..."),("tr","Reload bağlantısı kontrol ediliyor..."),("zh-CN","Ihlola ukuxhumeka ku-Reload..."),("zh-Hant","Ihlola ukuxhumeka ku-Reload..."))) diff --git a/Config/DefaultProfiles/athena.json b/Config/DefaultProfiles/athena.json index 2a33e77..344d655 100644 --- a/Config/DefaultProfiles/athena.json +++ b/Config/DefaultProfiles/athena.json @@ -504,5 +504,129 @@ "favorite_loadingscreen": "" } }, + "S11_GIFTS": { + "templateId": "AthenaRewardGraph:winterfest", + "attributes": { + "reward_nodes_claimed": [], + "unlock_epoch": "2021-12-16T13:52:10.000Z", + "unlock_keys_used": 0, + "player_random_seed": -2143043306, + "item_seen": false, + "player_state": [], + "reward_graph_purchased_timestamp": 1639693875638, + "reward_graph_purchased": true, + "reward_keys": [ + { + "static_key_template_id": "Token:athenawinterfest_key", + "static_key_max_count": 14, + "static_key_initial_count": 1, + "unlock_keys_used": 0 + } + ] + }, + "quantity": 1 + }, + "S11_GIFT_KEY": { + "templateId": "Token:athenawinterfest_key", + "attributes": { + "max_level_bonus": 0, + "level": 1, + "item_seen": false, + "xp": 0, + "favorite": false + }, + "quantity": 14 + }, + "AthenaRewardEventGraphCosmetic:REG_ID_001_Winterfest": { + "templateId": "AthenaRewardEventGraphCosmetic:REG_ID_001_Winterfest", + "attributes": { + "max_level_bonus": 0, + "level": 1, + "item_seen": 1, + "xp": 0, + "variants": [ + { + "channel": "RibbonType", + "active": "Mat1", + "owned": [ + "Mat1", + "Mat2" + ] + }, + { + "channel": "RibbonColor", + "active": "Mat1", + "owned": [ + "Mat1", + "Mat2", + "Mat3", + "Mat4", + "Mat5", + "Mat6", + "Mat7" + ] + }, + { + "channel": "WrappingColor", + "active": "Mat1", + "owned": [ + "Mat1", + "Mat2", + "Mat3", + "Mat4", + "Mat5", + "Mat6" + ] + }, + { + "channel": "NameTag", + "active": "Mat1", + "owned": [ + "Mat1", + "Mat2", + "Mat3", + "Mat4", + "Mat5", + "Mat6" + ] + }, + { + "channel": "WrappingStyle", + "active": "Mat1", + "owned": [ + "Mat1", + "Mat2", + "Mat3" + ] + }, + { + "channel": "Random", + "active": "Stage1", + "owned": [ + "Stage1", + "Stage2", + "Stage3", + "Stage4", + "Stage5", + "Stage6", + "Stage7" + ] + }, + { + "channel": "Defined", + "active": "Stage1", + "owned": [ + "Stage1", + "Stage2", + "Stage3", + "Stage4", + "Stage8" + ] + } + ], + "favorite": false + }, + "quantity": 1 + }, "commandRevision": 5 } \ No newline at end of file diff --git a/DiscordBot/commands/Admin/additem.js b/DiscordBot/commands/Admin/additem.js index 9ab86e8..35c3002 100644 --- a/DiscordBot/commands/Admin/additem.js +++ b/DiscordBot/commands/Admin/additem.js @@ -3,8 +3,9 @@ const Profiles = require('../../../model/profiles.js'); const fs = require('fs'); const path = require('path'); const destr = require('destr'); -const config = require('../../../Config/config.json') -const { MessageEmbed } = require('discord.js') +const config = require('../../../Config/config.json'); +const uuid = require("uuid"); +const { MessageEmbed } = require('discord.js'); module.exports = { commandInfo: { @@ -26,73 +27,144 @@ module.exports = { ] }, execute: async (interaction) => { - await interaction.deferReply({ ephemeral: true }); - - if (!config.moderators.includes(interaction.user.id)) { - return interaction.editReply({ content: "You do not have moderator permissions.", ephemeral: true }); - } + await interaction.deferReply({ ephemeral: true }); - const selectedUser = interaction.options.getUser('user'); - const selectedUserId = selectedUser.id; - const user = await Users.findOne({ discordId: selectedUserId }); - if (!user) - return interaction.editReply({ content: "That user does not own an account" }); - const profile = await Profiles.findOne({ accountId: user.accountId }); - if (!profile) - return interaction.editReply({ content: "That user does not own an account" }); - const cosmeticname = interaction.options.getString('cosmeticname'); - try { - await fetch(`https://fortnite-api.com/v2/cosmetics/br/search?name=${cosmeticname}`).then(res => res.json()).then(async (json) => { - const cosmeticFromAPI = json.data; - if (!cosmeticFromAPI) - return await interaction.editReply({ content: "Could not find the cosmetic" }); - const cosmeticimage = cosmeticFromAPI.images.icon; - const regex = /^(?:[A-Z][a-z]*\b\s*)+$/; - if (!regex.test(cosmeticname)) - return await interaction.editReply({ content: "Please check for correct casing. E.g 'renegade raider' is wrong, but 'Renegade Raider' is correct." }); - let cosmetic = {}; - const file = fs.readFileSync(path.join(__dirname, "../../../Config/DefaultProfiles/allathena.json")); - const jsonFile = destr(file.toString()); - const items = jsonFile.items; - let foundcosmeticname = ""; - let found = false; - for (const key of Object.keys(items)) { - const [type, id] = key.split(":"); - if (id === cosmeticFromAPI.id) { - foundcosmeticname = key; - if (profile.profiles.athena.items[key]) { - return await interaction.editReply({ content: "That user already has that cosmetic" }); + if (!config.moderators.includes(interaction.user.id)) { + return interaction.editReply({ content: "You do not have moderator permissions.", ephemeral: true }); + } + + const selectedUser = interaction.options.getUser('user'); + const selectedUserId = selectedUser.id; + const user = await Users.findOne({ discordId: selectedUserId }); + + if (!user) { + return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); + } + + const profile = await Profiles.findOne({ accountId: user.accountId }); + + if (!profile) { + return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); + } + + const cosmeticname = interaction.options.getString('cosmeticname'); + + try { + await fetch(`https://fortnite-api.com/v2/cosmetics/br/search?name=${cosmeticname}`) + .then(res => res.json()) + .then(async (json) => { + const cosmeticFromAPI = json.data; + if (!cosmeticFromAPI) { + return await interaction.editReply({ content: "Could not find the cosmetic", ephemeral: true }); } - found = true; - cosmetic = items[key]; - break; - } - } - if (!found) - return await interaction.editReply({ content: `Could not find the cosmetic ${cosmeticname}` }); - await Profiles.findOneAndUpdate({ accountId: user.accountId }, { - $set: { - [`profiles.athena.items.${foundcosmeticname}`]: cosmetic, - }, - }, { new: true }).catch(async (err) => { - console.log(err); - return await interaction.editReply({ content: "An error occured while adding the cosmetic" }); - }); - const embed = new MessageEmbed() - .setTitle("Cosmetic added") - .setDescription("Successfully gave the user the cosmetic **" + cosmeticname + "**") - .setThumbnail(cosmeticimage) - .setColor("GREEN") - .setFooter({ - text: "Reload Backend", - iconURL: "https://i.imgur.com/2RImwlb.png" - }) - .setTimestamp(); - await interaction.editReply({ embeds: [embed] }); - }); + + const cosmeticimage = cosmeticFromAPI.images.icon; + const regex = /^(?:[A-Z][a-z]*\b\s*)+$/; + if (!regex.test(cosmeticname)) { + return await interaction.editReply({ content: "Please check for correct casing. E.g 'Renegade Raider' is correct.", ephemeral: true }); + } + + let cosmetic = {}; + const file = fs.readFileSync(path.join(__dirname, "../../../Config/DefaultProfiles/allathena.json")); + const jsonFile = destr(file.toString()); + const items = jsonFile.items; + let foundcosmeticname = ""; + let found = false; + + for (const key of Object.keys(items)) { + const [type, id] = key.split(":"); + if (id === cosmeticFromAPI.id) { + foundcosmeticname = key; + if (profile.profiles.athena.items[key]) { + return await interaction.editReply({ content: "That user already has that cosmetic", ephemeral: true }); + } + found = true; + cosmetic = items[key]; + break; + } + } + + if (!found) { + return await interaction.editReply({ content: `Could not find the cosmetic ${cosmeticname}`, ephemeral: true }); + } + + const purchaseId = uuid.v4(); + const lootList = [{ + "itemType": cosmetic.templateId, + "itemGuid": cosmetic.templateId, + "quantity": 1 + }]; + + const common_core = profile.profiles["common_core"]; + const athena = profile.profiles["athena"]; + + common_core.items[purchaseId] = { + "templateId": `GiftBox:GB_MakeGood`, + "attributes": { + "fromAccountId": `[${interaction.user.username}]`, + "lootList": lootList, + "params": { + "userMessage": `Thanks For Using Reload Backend!` + }, + "giftedOn": new Date().toISOString() + }, + "quantity": 1 + }; + + athena.items[foundcosmeticname] = cosmetic; + + let ApplyProfileChanges = [ + { + "changeType": "itemAdded", + "itemId": foundcosmeticname, + "templateId": cosmetic.templateId + }, + { + "changeType": "itemAdded", + "itemId": purchaseId, + "templateId": "GiftBox:GB_MakeGood" + } + ]; + + common_core.rvn++; + common_core.commandRevision++; + common_core.updated = new Date().toISOString(); + athena.rvn++; + athena.commandRevision++; + athena.updated = new Date().toISOString(); + + await Profiles.updateOne( + { accountId: user.accountId }, + { + $set: { + 'profiles.common_core': common_core, + 'profiles.athena': athena + } + } + ); + + const embed = new MessageEmbed() + .setTitle("Cosmetic Gift Sent") + .setDescription(`Successfully gave the user the cosmetic **${cosmeticname}** with a GiftBox`) + .setThumbnail(cosmeticimage) + .setColor("GREEN") + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }) + .setTimestamp(); + + await interaction.editReply({ embeds: [embed], ephemeral: true }); + + return { + profileRevision: common_core.rvn, + profileCommandRevision: common_core.commandRevision, + profileChanges: ApplyProfileChanges + }; + }); + } catch (err) { + console.log(err); + await interaction.editReply({ content: "An unexpected error occurred", ephemeral: true }); + } } - catch (err) { - console.log(err); - } - } -}; \ No newline at end of file +}; diff --git a/DiscordBot/commands/Admin/addvbucks.js b/DiscordBot/commands/Admin/addvbucks.js index fe22b03..5adbd49 100644 --- a/DiscordBot/commands/Admin/addvbucks.js +++ b/DiscordBot/commands/Admin/addvbucks.js @@ -1,55 +1,124 @@ const Users = require('../../../model/user'); const Profiles = require('../../../model/profiles'); -const config = require('../../../Config/config.json') +const config = require('../../../Config/config.json'); +const uuid = require("uuid"); const { MessageEmbed } = require("discord.js"); module.exports = { commandInfo: { name: "addvbucks", - description: "Lets you change a users amount of vbucks", + description: "Lets you change a user's amount of V-Bucks", options: [ { name: "user", - description: "The user you want to change the vbucks of", + description: "The user you want to change the V-Bucks of", required: true, type: 6 }, { name: "vbucks", - description: "The amount of vbucks you want to give (Can be a negative number to take vbucks)", + description: "The amount of V-Bucks you want to give (Can be negative to deduct V-Bucks)", required: true, type: 4 } ] }, execute: async (interaction) => { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - if (!config.moderators.includes(interaction.user.id)) { - return interaction.editReply({ content: "You do not have moderator permissions.", ephemeral: true }); + if (!config.moderators.includes(interaction.user.id)) { + return interaction.editReply({ content: "You do not have moderator permissions.", ephemeral: true }); + } + + const selectedUser = interaction.options.getUser('user'); + const selectedUserId = selectedUser?.id; + const user = await Users.findOne({ discordId: selectedUserId }); + + if (!user) { + return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); + } + + const vbucks = parseInt(interaction.options.getInteger('vbucks')); + if (isNaN(vbucks) || vbucks === 0) { + return interaction.editReply({ content: "Invalid V-Bucks amount specified.", ephemeral: true }); + } + + const filter = { accountId: user.accountId }; + const update = { $inc: { 'profiles.common_core.items.Currency:MtxPurchased.quantity': vbucks } }; + const options = { new: true }; + + const updatedProfile = await Profiles.findOneAndUpdate(filter, update, options); + if (!updatedProfile) { + return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); + } + + const common_core = updatedProfile.profiles["common_core"]; + const newQuantity = common_core.items['Currency:MtxPurchased'].quantity; + + if (newQuantity < 0 || newQuantity >= 1000000) { + return interaction.editReply({ + content: "V-Bucks amount is out of valid range after the update.", + ephemeral: true + }); + } + + const purchaseId = uuid.v4(); + const lootList = [{ + "itemType": "Currency:MtxGiveaway", + "itemGuid": "Currency:MtxGiveaway", + "quantity": vbucks + }]; + + common_core.items[purchaseId] = { + "templateId": `GiftBox:GB_MakeGood`, + "attributes": { + "fromAccountId": `[Administrator]`, + "lootList": lootList, + "params": { + "userMessage": `Thanks For Using Reload Backend!` + }, + "giftedOn": new Date().toISOString() + }, + "quantity": 1 + }; + + let ApplyProfileChanges = [ + { + "changeType": "itemQuantityChanged", + "itemId": "Currency:MtxPurchased", + "quantity": newQuantity + }, + { + "changeType": "itemAdded", + "itemId": purchaseId, + "templateId": "GiftBox:GB_MakeGood" + } + ]; + + common_core.rvn += 1; + common_core.commandRevision += 1; + common_core.updated = new Date().toISOString(); + + await Profiles.updateOne(filter, { $set: { 'profiles.common_core': common_core } }); + + const embed = new MessageEmbed() + .setTitle("V-Bucks Updated") + .setDescription(`Successfully added **${vbucks}** V-Bucks to <@${selectedUserId}> with a GiftBox`) + .setThumbnail("https://i.imgur.com/yLbihQa.png") + .setColor("GREEN") + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }) + .setTimestamp(); + + await interaction.editReply({ embeds: [embed], ephemeral: true }); + + return { + profileRevision: common_core.rvn, + profileCommandRevision: common_core.commandRevision, + profileChanges: ApplyProfileChanges, + newQuantity + }; } - - const selectedUser = interaction.options.getUser('user'); - const selectedUserId = selectedUser?.id; - const user = await Users.findOne({ discordId: selectedUserId }); - if (!user) - return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); - const vbucks = parseInt(interaction.options.getInteger('vbucks')); - const profile = await Profiles.findOneAndUpdate({ accountId: user.accountId }, { $inc: { 'profiles.common_core.items.Currency:MtxPurchased.quantity': vbucks } }); - if (!profile) - return interaction.editReply({ content: "That user does not own an account", ephemeral: true }); - - const embed = new MessageEmbed() - .setTitle("Vbucks Changed") - .setDescription("Successfully changed the amount of vbucks for <@" + selectedUserId + "> to **" + vbucks + "**") - .setThumbnail("https://i.imgur.com/yLbihQa.png") - .setColor("GREEN") - .setFooter({ - text: "Reload Backend", - iconURL: "https://i.imgur.com/2RImwlb.png" - }) - .setTimestamp(); - - await interaction.editReply({ embeds: [embed], ephemeral: true }); - } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/DiscordBot/commands/Admin/createhostaccount.js b/DiscordBot/commands/Admin/createhostaccount.js new file mode 100644 index 0000000..36d2185 --- /dev/null +++ b/DiscordBot/commands/Admin/createhostaccount.js @@ -0,0 +1,78 @@ +const { MessageEmbed } = require("discord.js"); +const functions = require("../../../structs/functions.js"); +const User = require("../../../model/user.js"); + +module.exports = { + commandInfo: { + name: "createhostaccount", + description: "Creates a host account for Reload Backend." + }, + execute: async (interaction) => { + await interaction.deferReply({ ephemeral: true }); + + const serverOwnerId = interaction.guild.ownerId; + + if (interaction.user.id !== serverOwnerId) { + return interaction.editReply({ + content: "Only the server owner can execute this command.", + ephemeral: true + }); + } + + const existingHostAccount = await User.findOne({ email: "hostaccount@reloadbackend.com" }); + + if (existingHostAccount) { + return interaction.editReply({ + content: "A host account has already been created.", + ephemeral: true + }); + } + + const username = "reloadbackendhostaccount"; + const email = "hostaccount@reloadbackend.com"; + const password = generateRandomPassword(12); + + try { + await functions.registerUser(null, username, email, password).then(async (resp) => { + let embed = new MessageEmbed() + .setColor(resp.status >= 400 ? "#ff0000" : "#56ff00") + .addFields( + { name: "Message", value: resp.message }, + { name: "Username", value: `\`\`\`${username}\`\`\`` }, + { name: "Email", value: `\`\`\`${email}\`\`\`` }, + { name: "Password", value: `\`\`\`${password}\`\`\`` }, + ) + .setTimestamp() + .setFooter({ + text: "Reload Backend", + iconURL: "https://i.imgur.com/2RImwlb.png" + }); + + if (resp.status >= 400) { + return interaction.editReply({ embeds: [embed], ephemeral: true }); + } + + await interaction.editReply({ + embeds: [embed], + ephemeral: true + }); + }); + } catch (error) { + console.error(error); + return interaction.editReply({ + content: "An error occurred while creating the host account.", + ephemeral: true + }); + } + } +}; + +function generateRandomPassword(length) { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+<>?"; + let password = ""; + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * charset.length); + password += charset[randomIndex]; + } + return password; +} \ No newline at end of file diff --git a/DiscordBot/commands/Admin/delete.js b/DiscordBot/commands/Admin/delete.js index 35bc252..9f83162 100644 --- a/DiscordBot/commands/Admin/delete.js +++ b/DiscordBot/commands/Admin/delete.js @@ -2,6 +2,7 @@ const { MessageEmbed } = require("discord.js"); const Users = require('../../../model/user.js'); const Profiles = require('../../../model/profiles.js'); const SACCodes = require('../../../model/saccodes.js'); +const Friends = require('../../../model/friends.js'); const config = require('../../../Config/config.json'); module.exports = { @@ -33,8 +34,15 @@ module.exports = { return; } - await Users.deleteOne({ username: username }); - await Profiles.deleteOne({ username: username }); + await Users.deleteOne({ username: username }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); + await Profiles.deleteOne({ accountId: accountId }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); + await Friends.deleteOne({ accountId: accountId }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); await SACCodes.deleteOne({ owneraccountId: accountId }).catch(error => { // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); }); diff --git a/DiscordBot/commands/Admin/deletediscord.js b/DiscordBot/commands/Admin/deletediscord.js index 7815d3b..b4eadf2 100644 --- a/DiscordBot/commands/Admin/deletediscord.js +++ b/DiscordBot/commands/Admin/deletediscord.js @@ -2,6 +2,7 @@ const { MessageEmbed } = require("discord.js"); const Users = require('../../../model/user.js'); const Profiles = require('../../../model/profiles.js'); const SACCodes = require('../../../model/saccodes.js'); +const Friends = require('../../../model/friends.js'); const config = require('../../../Config/config.json') module.exports = { @@ -34,8 +35,15 @@ module.exports = { return; } - await Users.deleteOne({ discordId: discordId }) - await Profiles.deleteOne({ discordId: discordId }) + await Users.deleteOne({ username: username }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); + await Profiles.deleteOne({ accountId: accountId }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); + await Friends.deleteOne({ accountId: accountId }).catch(error => { + // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); + }); await SACCodes.deleteOne({ owneraccountId: accountId }).catch(error => { // Nothing Uwu or just use: log.debug('No SAC codes found or error occurred:', error); }); diff --git a/DiscordBot/commands/Admin/removeitem.js b/DiscordBot/commands/Admin/removeitem.js index 15a180f..4807016 100644 --- a/DiscordBot/commands/Admin/removeitem.js +++ b/DiscordBot/commands/Admin/removeitem.js @@ -100,7 +100,7 @@ module.exports = { const embed = new MessageEmbed() .setTitle("Cosmetic Removed") - .setDescription(`Successfully removed for <@${selectedUser}> the cosmetic **` + cosmeticname + `**`) + .setDescription(`Successfully removed for ${selectedUser} the cosmetic **` + cosmeticname + `**`) .setThumbnail(cosmeticimage) .setColor("GREEN") .setFooter({ diff --git a/DiscordBot/commands/User/change-email.js b/DiscordBot/commands/User/change-email.js index f680636..fcd36e7 100644 --- a/DiscordBot/commands/User/change-email.js +++ b/DiscordBot/commands/User/change-email.js @@ -1,5 +1,6 @@ const { MessageEmbed } = require("discord.js"); const Users = require('../../../model/user.js'); +const functions = require("../../../structs/functions.js"); module.exports = { commandInfo: { @@ -18,8 +19,10 @@ module.exports = { await interaction.deferReply({ ephemeral: true }); const user = await Users.findOne({ discordId: interaction.user.id }); - if (!user) + if (!user) { return interaction.editReply({ content: "You are not registered!", ephemeral: true }); + } + const plainEmail = interaction.options.getString('email'); const emailFilter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; @@ -31,17 +34,34 @@ module.exports = { if (existingUser) { return interaction.editReply({ content: "Email is already in use, please choose another one.", ephemeral: true }); } - + await user.updateOne({ $set: { email: plainEmail } }); + + const refreshTokenIndex = global.refreshTokens.findIndex(i => i.accountId == user.accountId); + if (refreshTokenIndex != -1) global.refreshTokens.splice(refreshTokenIndex, 1); + + const accessTokenIndex = global.accessTokens.findIndex(i => i.accountId == user.accountId); + if (accessTokenIndex != -1) { + global.accessTokens.splice(accessTokenIndex, 1); + + const xmppClient = global.Clients.find(client => client.accountId == user.accountId); + if (xmppClient) xmppClient.client.close(); + } + + if (accessTokenIndex != -1 || refreshTokenIndex != -1) { + await functions.UpdateTokens(); + } + const embed = new MessageEmbed() .setTitle("Email changed") - .setDescription("Your account email has been changed") + .setDescription("Your account email has been changed.") .setColor("GREEN") .setFooter({ text: "Reload Backend", iconURL: "https://i.imgur.com/2RImwlb.png", }) .setTimestamp(); + await interaction.editReply({ embeds: [embed], ephemeral: true }); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/DiscordBot/commands/User/change-password.js b/DiscordBot/commands/User/change-password.js index bd1062f..e95b0a3 100644 --- a/DiscordBot/commands/User/change-password.js +++ b/DiscordBot/commands/User/change-password.js @@ -1,6 +1,7 @@ const { MessageEmbed } = require("discord.js"); const User = require("../../../model/user.js"); const bcrypt = require("bcrypt"); +const functions = require("../../../structs/functions.js"); module.exports = { commandInfo: { @@ -21,9 +22,7 @@ module.exports = { const user = await User.findOne({ discordId: interaction.user.id }); if (!user) return interaction.editReply({ content: "You do not have a registered account!", ephemeral: true }); - const { options } = interaction; - - let plainPassword = options.get("password").value; + const plainPassword = interaction.options.get("password").value; if (plainPassword.length >= 128) { return interaction.editReply({ content: "Your password must be less than 128 characters long.", ephemeral: true }); @@ -32,19 +31,34 @@ module.exports = { return interaction.editReply({ content: "Your password must be at least 4 characters long.", ephemeral: true }); } - let hashedPassword = await bcrypt.hash(plainPassword, 10); - + const hashedPassword = await bcrypt.hash(plainPassword, 10); await user.updateOne({ $set: { password: hashedPassword } }); + const refreshTokenIndex = global.refreshTokens.findIndex(i => i.accountId == user.accountId); + if (refreshTokenIndex != -1) global.refreshTokens.splice(refreshTokenIndex, 1); + + const accessTokenIndex = global.accessTokens.findIndex(i => i.accountId == user.accountId); + if (accessTokenIndex != -1) { + global.accessTokens.splice(accessTokenIndex, 1); + + const xmppClient = global.Clients.find(client => client.accountId == user.accountId); + if (xmppClient) xmppClient.client.close(); + } + + if (accessTokenIndex != -1 || refreshTokenIndex != -1) { + await functions.UpdateTokens(); + } + const embed = new MessageEmbed() .setTitle("Password changed") - .setDescription("Your account password has been changed") + .setDescription("Your account password has been changed.") .setColor("GREEN") .setFooter({ text: "Reload Backend", iconURL: "https://i.imgur.com/2RImwlb.png", }) .setTimestamp(); + await interaction.editReply({ embeds: [embed], ephemeral: true }); } -} \ No newline at end of file +}; diff --git a/DiscordBot/commands/User/change-username.js b/DiscordBot/commands/User/change-username.js index bc3ed46..dd58ad1 100644 --- a/DiscordBot/commands/User/change-username.js +++ b/DiscordBot/commands/User/change-username.js @@ -1,6 +1,7 @@ const { MessageEmbed } = require("discord.js"); const User = require("../../../model/user.js"); const Badwords = require("bad-words"); +const functions = require("../../../structs/functions.js"); const badwords = new Badwords(); @@ -25,13 +26,11 @@ module.exports = { return interaction.editReply({ content: "You are not registered!", ephemeral: true }); const username = interaction.options.getString('username'); - if (!badwords.isProfane(username)) { + if (badwords.isProfane(username)) { return interaction.editReply({ content: "Invalid username. Username must not contain inappropriate language." }); } - const plainUsername = interaction.options.getString('username'); - - const existingUser = await User.findOne({ username: plainUsername }); + const existingUser = await User.findOne({ username: username }); if (existingUser) { return interaction.editReply({ content: "Username already exists. Please choose a different one.", ephemeral: true }); } @@ -44,15 +43,31 @@ module.exports = { await user.updateOne({ $set: { username: username, username_lower: username.toLowerCase() } }); + const refreshTokenIndex = global.refreshTokens.findIndex(i => i.accountId == user.accountId); + if (refreshTokenIndex != -1) global.refreshTokens.splice(refreshTokenIndex, 1); + + const accessTokenIndex = global.accessTokens.findIndex(i => i.accountId == user.accountId); + if (accessTokenIndex != -1) { + global.accessTokens.splice(accessTokenIndex, 1); + + const xmppClient = global.Clients.find(client => client.accountId == user.accountId); + if (xmppClient) xmppClient.client.close(); + } + + if (accessTokenIndex != -1 || refreshTokenIndex != -1) { + await functions.UpdateTokens(); + } + const embed = new MessageEmbed() .setTitle("Username changed") - .setDescription(`Your account username has been changed to **${username}**`) + .setDescription(`Your account username has been changed to **${username}**.`) .setColor("GREEN") .setFooter({ text: "Reload Backend", iconURL: "https://i.imgur.com/2RImwlb.png", }) .setTimestamp(); + await interaction.editReply({ embeds: [embed], ephemeral: true }); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/README.md b/README.md index 877ac0f..1c069fd 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ This **project/backend** is licensed under the **BSD 3-Clause License.** * [Burlone](https://github.com/burlone0) - For having modded most things, let's say he modded everything * [NotTacos](https://github.com/PhysicalDrive) - For adding the working challenges (Backend Part) * [zvivsp](https://github.com/zvivsp) - For creating the graphics +* [Waslyl](https://github.com/Waslyl) - For helping with some fixes * [joaco](https://github.com/ojotaa0124) - For helping with CloudStorage and responses stuff * [VoxyB89](https://github.com/VoxyB89) - For adding https/ssl support * [xLoigi](https://github.com/xLoigi) - For helping with some files and support a creator stuff and for creating Caldera Service diff --git a/model/user.js b/model/user.js index 7e2b2d5..5283e52 100644 --- a/model/user.js +++ b/model/user.js @@ -4,7 +4,7 @@ const UserSchema = new mongoose.Schema( { created: { type: Date, required: true }, banned: { type: Boolean, default: false }, - discordId: { type: String, required: true, unique: true }, + discordId: { type: String, default: null, unique: true, sparse: true }, accountId: { type: String, required: true, unique: true }, username: { type: String, required: true, unique: true }, username_lower: { type: String, required: true, unique: true }, diff --git a/package-lock.json b/package-lock.json index 4a425a5..f5ad83d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "reloadbackend", - "version": "1.0.9", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "reloadbackend", - "version": "1.0.9", + "version": "1.1.0", "license": "BSD-3-Clause license", "dependencies": { "axios": "^1.7.7", diff --git a/package.json b/package.json index 7a33054..d3f6b17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reloadbackend", - "version": "1.0.9", + "version": "1.1.0", "description": "Created by Burlone, This is a modded backend, all main backend credits to lawin", "main": "index.js", "dependencies": { diff --git a/routes/mcp.js b/routes/mcp.js index 43eef19..a94d28c 100644 --- a/routes/mcp.js +++ b/routes/mcp.js @@ -1683,7 +1683,7 @@ app.post("/fortnite/api/game/v2/profile/*/client/PurchaseCatalogEntry", verifyTo }; profiles.profiles["common_core"].items[tokenKey] = tokenData; - c + ApplyProfileChanges.push({ "changeType": "itemAdded", "itemId": tokenKey, diff --git a/structs/functions.js b/structs/functions.js index c7dccdf..5efc73f 100644 --- a/structs/functions.js +++ b/structs/functions.js @@ -313,20 +313,24 @@ function getPresenceFromUser(fromId, toId, offline) { async function registerUser(discordId, username, email, plainPassword) { email = email.toLowerCase(); - if (!discordId || !username || !email || !plainPassword) { + if (!username || !email || !plainPassword) { return { message: "Username, email, or password is required.", status: 400 }; } - if (await User.findOne({ discordId })) { + if (discordId && await User.findOne({ discordId })) { return { message: "You already created an account!", status: 400 }; } + if (await User.findOne({ email })) { + return { message: "Email is already in use.", status: 400 }; + } + const accountId = MakeID().replace(/-/ig, ""); const matchmakingId = MakeID().replace(/-/ig, ""); const emailFilter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; if (!emailFilter.test(email)) { - return { message: "You did not provide a valid email address!", status: 400 }; + return { message: "You did not provide a valid email address.", status: 400 }; } if (username.length >= 25) { return { message: "Your username must be less than 25 characters long.", status: 400 }; @@ -342,7 +346,6 @@ async function registerUser(discordId, username, email, plainPassword) { } const allowedCharacters = (" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~").split(""); - for (let character of username) { if (!allowedCharacters.includes(character)) { return { message: "Your username has special characters, please remove them and try again.", status: 400 }; @@ -352,7 +355,16 @@ async function registerUser(discordId, username, email, plainPassword) { const hashedPassword = await bcrypt.hash(plainPassword, 10); try { - await User.create({ created: new Date().toISOString(), discordId, accountId, username, username_lower: username.toLowerCase(), email, password: hashedPassword, matchmakingId }).then(async (i) => { + await User.create({ + created: new Date().toISOString(), + discordId: discordId || null, + accountId, + username, + username_lower: username.toLowerCase(), + email, + password: hashedPassword, + matchmakingId + }).then(async (i) => { await Profile.create({ created: i.created, accountId: i.accountId, profiles: profileManager.createProfiles(i.accountId) }); await Friends.create({ created: i.created, accountId: i.accountId }); }); @@ -364,7 +376,7 @@ async function registerUser(discordId, username, email, plainPassword) { return { message: "An unknown error has occurred, please try again later.", status: 400 }; } - return { message: `Successfully created an account with the username ${username}`, status: 200 }; + return { message: `Successfully created an account with the username **${username}**`, status: 200 }; } async function createSAC(code, username, creator) {