From c9a5f468da34e5749ec7678e9e5ac97f07999825 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Wed, 28 Jul 2021 20:13:31 +0200 Subject: [PATCH] Add Steamwar Discord Auth --- src/de/steamwar/bungeecore/BungeeCore.java | 1 + .../steamwar/bungeecore/bot/AuthManager.java | 75 +++++++++++++++++++ .../bungeecore/bot/SteamwarDiscordBot.java | 4 + .../bot/listeners/DiscordAuthListener.java | 59 +++++++++++++++ .../bot/listeners/DiscordTicketListener.java | 6 +- .../RolesInteractionButtonListener.java | 3 +- .../bot/util/DiscordRulesMessage.java | 5 +- .../bungeecore/commands/VerifyCommand.java | 60 +++++++++++++++ .../steamwar/bungeecore/sql/SteamwarUser.java | 25 +++++++ .../steamwar/messages/BungeeCore.properties | 7 +- 10 files changed, 237 insertions(+), 8 deletions(-) create mode 100644 src/de/steamwar/bungeecore/bot/AuthManager.java create mode 100644 src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java create mode 100644 src/de/steamwar/bungeecore/commands/VerifyCommand.java diff --git a/src/de/steamwar/bungeecore/BungeeCore.java b/src/de/steamwar/bungeecore/BungeeCore.java index 72e58395..8a457e29 100644 --- a/src/de/steamwar/bungeecore/BungeeCore.java +++ b/src/de/steamwar/bungeecore/BungeeCore.java @@ -126,6 +126,7 @@ public class BungeeCore extends Plugin { new ResourcereloadCommand(); new ListCommand(); new StatCommand(); + new VerifyCommand(); if(!EVENT_MODE){ new WebregisterCommand(); diff --git a/src/de/steamwar/bungeecore/bot/AuthManager.java b/src/de/steamwar/bungeecore/bot/AuthManager.java new file mode 100644 index 00000000..19b2cdb2 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/AuthManager.java @@ -0,0 +1,75 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot; + +import de.steamwar.bungeecore.BungeeCore; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.Button; +import net.md_5.bungee.api.scheduler.ScheduledTask; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class AuthManager { + + private static final Map TOKENS = new HashMap<>(); + private static final Random rand = new Random(); + + public static String createDiscordAuthToken(Member member) { + if(TOKENS.containsValue(member.getIdLong())) return null; + + byte[] randBytes = new byte[16]; + rand.nextBytes(randBytes); + randBytes[0] = 'D'; + randBytes[1] = 'C'; + String code = Base64.getEncoder().encodeToString(randBytes); + + TOKENS.put(code, member.getIdLong()); + BungeeCore.log("Created Discord Auth-Token: " + code + " for: " + member.getUser().getAsTag()); + ScheduledTask[] task = new ScheduledTask[1]; + task[0] = BungeeCore.get().getProxy().getScheduler().schedule(BungeeCore.get(), () -> { + TOKENS.remove(code); + task[0].cancel(); + }, 10, 10, TimeUnit.MINUTES); + return code; + } + + public static Member connectAuth(SteamwarUser user, String code) { + if (TOKENS.containsKey(code)) { + Member member = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).retrieveMemberById(TOKENS.get(code).longValue()).complete(); + if(member == null) return null; + user.setDiscordId(member.getId()); + MessageBuilder builder = new MessageBuilder(); + builder.setContent(":white_check_mark: Dein Discord Konto wurde mit **" + user.getUserName() + "** verknüpft"); + builder.setActionRows(ActionRow.of(Button.success("tada", Emoji.fromUnicode("U+1F389")), Button.danger("invalid", "Ich war das nicht"))); + + member.getUser().openPrivateChannel().complete().sendMessage(builder.build()).complete(); + TOKENS.remove(code); + return member; + } else { + return null; + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java b/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java index 2e338ae8..9d458e51 100644 --- a/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java +++ b/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java @@ -23,6 +23,7 @@ import de.steamwar.bungeecore.BungeeCore; import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; import de.steamwar.bungeecore.bot.events.EventManager; import de.steamwar.bungeecore.bot.listeners.AnnouncementListener; +import de.steamwar.bungeecore.bot.listeners.DiscordAuthListener; import de.steamwar.bungeecore.bot.listeners.DiscordTicketListener; import de.steamwar.bungeecore.bot.listeners.RolesInteractionButtonListener; import de.steamwar.bungeecore.bot.util.DiscordTicketMessage; @@ -35,6 +36,7 @@ import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.md_5.bungee.api.ProxyServer; import javax.security.auth.login.LoginException; @@ -58,6 +60,7 @@ public class SteamwarDiscordBot { INSTANCE = this; JDABuilder builder = JDABuilder.createDefault(SteamwarDiscordBotConfig.TOKEN); builder.setStatus(OnlineStatus.ONLINE); + builder.setMemberCachePolicy(MemberCachePolicy.ONLINE); try { jda = builder.build(); } catch (LoginException e) { @@ -80,6 +83,7 @@ public class SteamwarDiscordBot { new RolesInteractionButtonListener(); new DiscordTicketListener(); + new DiscordAuthListener(); announcementListener = new AnnouncementListener(); } diff --git a/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java b/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java new file mode 100644 index 00000000..18458ef3 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java @@ -0,0 +1,59 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.AuthManager; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent; +import net.dv8tion.jda.api.interactions.InteractionType; +import org.jetbrains.annotations.NotNull; + +public class DiscordAuthListener extends BasicDiscordListener { + + @Override + public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { + if(event.getType() == InteractionType.COMPONENT) { + if(event.getChannel().getId().equals(SteamwarDiscordBotConfig.RULES_CHANNEL) && event.getComponentId().equals("auth")) { + String authMessage = AuthManager.createDiscordAuthToken(event.getMember()); + if(authMessage != null) { + event.reply("Gebe innerhalb der nächsten 10 Minuten ``/verify " + authMessage + "`` ein!").setEphemeral(true).complete(); + } else { + event.reply("Du hast bereits einen Code am laufen").setEphemeral(true).complete(); + } + } + + if(event.getComponentId().equals("tada") && event.getChannelType() == ChannelType.PRIVATE) { + event.reply(":tada:").setEphemeral(false).complete(); + } + + if(event.getComponentId().equals("invalid") && event.getChannelType() == ChannelType.PRIVATE) { + SteamwarUser user = SteamwarUser.get(event.getUser().getIdLong()); + if(user == null) { + event.reply(":questionmark: Da ist keine verknüpfung?").setEphemeral(false).complete(); + } else { + user.setDiscordId(null); + event.reply(":x: Die Verknüpfung wurde beendet").setEphemeral(false).complete(); + } + } + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java b/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java index 0b9b9399..7ba2e4ec 100644 --- a/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java +++ b/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java @@ -29,21 +29,17 @@ import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateE import net.dv8tion.jda.api.interactions.InteractionType; import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.Button; -import net.dv8tion.jda.api.requests.restaction.MessageAction; import org.jetbrains.annotations.NotNull; import java.awt.Color; -import java.io.File; import java.time.Instant; -import java.util.ArrayList; import java.util.LinkedList; -import java.util.List; public class DiscordTicketListener extends BasicDiscordListener { @Override public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { - if(event.getType() == InteractionType.COMPONENT && event.getTextChannel().getParent().getId().equals(SteamwarDiscordBotConfig.TICKET_CATEGORY)) { + if(event.getType() == InteractionType.COMPONENT && event.getChannelType() == ChannelType.TEXT && event.getTextChannel().getParent() != null && event.getTextChannel().getParent().getId().equals(SteamwarDiscordBotConfig.TICKET_CATEGORY)) { if(event.getTextChannel().getId().equals(SteamwarDiscordBotConfig.TICKET_CHANNEL) && SteamwarDiscordBotConfig.TICKET_TYPES.containsKey(event.getComponentId())) { DiscordTicketType ticketType = SteamwarDiscordBotConfig.TICKET_TYPES.get(event.getComponentId()); Category ct = event.getGuild().getCategoryById(SteamwarDiscordBotConfig.TICKET_CATEGORY); diff --git a/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java b/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java index 0790a07d..035cd77c 100644 --- a/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java +++ b/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java @@ -20,6 +20,7 @@ package de.steamwar.bungeecore.bot.listeners; import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent; import net.dv8tion.jda.api.interactions.InteractionType; import org.jetbrains.annotations.NotNull; @@ -28,7 +29,7 @@ public class RolesInteractionButtonListener extends BasicDiscordListener { @Override public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { - if(event.getType() == InteractionType.COMPONENT && event.getTextChannel().getId().equals(SteamwarDiscordBotConfig.ROLES_CHANNEL) && SteamwarDiscordBotConfig.ROLES.stream().anyMatch(discordRole -> discordRole.getRoleId().equals(event.getComponentId()))) { + if(event.getType() == InteractionType.COMPONENT && event.getChannelType() == ChannelType.TEXT && event.getTextChannel().getId().equals(SteamwarDiscordBotConfig.ROLES_CHANNEL) && SteamwarDiscordBotConfig.ROLES.stream().anyMatch(discordRole -> discordRole.getRoleId().equals(event.getComponentId()))) { if (event.getMember().getRoles().stream().anyMatch(role -> role.getId().equals(event.getComponentId()))) { event.getGuild().removeRoleFromMember(event.getMember(), event.getGuild().getRoleById(event.getComponentId())).complete(); event.reply(SteamwarDiscordBotConfig.ROLES_REMOVED.replace("%role%", event.getGuild().getRoleById(event.getComponentId()).getAsMention())).setEphemeral(true).complete(); diff --git a/src/de/steamwar/bungeecore/bot/util/DiscordRulesMessage.java b/src/de/steamwar/bungeecore/bot/util/DiscordRulesMessage.java index c27a4afc..0ef229b5 100644 --- a/src/de/steamwar/bungeecore/bot/util/DiscordRulesMessage.java +++ b/src/de/steamwar/bungeecore/bot/util/DiscordRulesMessage.java @@ -23,6 +23,7 @@ import de.steamwar.bungeecore.bot.SteamwarDiscordBot; import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.Button; @@ -49,9 +50,11 @@ public class DiscordRulesMessage { List