diff --git a/pom.xml b/pom.xml index f800c25c4..8d3ebd32e 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,13 @@ 6.1.0-TF + + net.dv8tion + JDA + 3.8.0_423 + provided + + diff --git a/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java b/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java index 04011fc16..1d72516b5 100644 --- a/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java +++ b/src/main/java/me/totalfreedom/totalfreedommod/TotalFreedomMod.java @@ -21,6 +21,7 @@ import me.totalfreedom.totalfreedommod.caging.Cager; import me.totalfreedom.totalfreedommod.command.CommandLoader; import me.totalfreedom.totalfreedommod.config.MainConfig; +import me.totalfreedom.totalfreedommod.discord.Discord; import me.totalfreedom.totalfreedommod.freeze.Freezer; import me.totalfreedom.totalfreedommod.fun.ItemFun; import me.totalfreedom.totalfreedommod.fun.Jumppads; @@ -74,6 +75,7 @@ public class TotalFreedomMod extends AeroPlugin public PlayerList pl; public Announcer an; public ChatManager cm; + public Discord dc; public BanManager bm; public PermbanList pm; public ProtectArea pa; @@ -167,6 +169,7 @@ public void enable() pl = services.registerService(PlayerList.class); an = services.registerService(Announcer.class); cm = services.registerService(ChatManager.class); + dc = services.registerService(Discord.class); bm = services.registerService(BanManager.class); pm = services.registerService(PermbanList.class); pa = services.registerService(ProtectArea.class); diff --git a/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java b/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java index 35b61d631..97f9acbd6 100644 --- a/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java +++ b/src/main/java/me/totalfreedom/totalfreedommod/admin/Admin.java @@ -39,6 +39,9 @@ public class Admin implements ConfigLoadable, ConfigSavable, Validatable @Getter @Setter private String loginMessage = null; + @Getter + @Setter + private String discordID = null; public Admin(Player player) { @@ -62,7 +65,8 @@ public String toString() .append("- Last Login: ").append(FUtil.dateToString(lastLogin)).append("\n") .append("- Custom Login Message: ").append(loginMessage).append("\n") .append("- Rank: ").append(rank.getName()).append("\n") - .append("- Is Active: ").append(active); + .append("- Is Active: ").append(active) + .append("- Discord ID: ").append(discordID).append("\n"); return output.toString(); } @@ -85,6 +89,7 @@ public void loadFrom(ConfigurationSection cs) ips.addAll(cs.getStringList("ips")); lastLogin = FUtil.stringToDate(cs.getString("last_login")); loginMessage = cs.getString("login_message", null); + discordID = cs.getString("discord_id", null); } @Override @@ -97,6 +102,7 @@ public void saveTo(ConfigurationSection cs) cs.set("ips", Lists.newArrayList(ips)); cs.set("last_login", FUtil.dateToString(lastLogin)); cs.set("login_message", loginMessage); + cs.set("discord_id", discordID); } public boolean isAtLeast(Rank pRank) diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java new file mode 100644 index 000000000..7cbdc0c53 --- /dev/null +++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_linkdiscord.java @@ -0,0 +1,50 @@ +package me.totalfreedom.totalfreedommod.command; + +import java.util.Random; +import me.totalfreedom.totalfreedommod.admin.Admin; +import me.totalfreedom.totalfreedommod.discord.Discord; +import me.totalfreedom.totalfreedommod.rank.Rank; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@CommandPermissions(level = Rank.SUPER_ADMIN, source = SourceType.ONLY_IN_GAME) +@CommandParameters(description = "Link your Discord account to your Minecraft account", usage = "/") +public class Command_linkdiscord extends FreedomCommand +{ + + @Override + public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole) + { + if (!plugin.dc.enabled) + { + msg("The Discord verification system is currently disabled.", ChatColor.RED); + return true; + } + + Admin admin = plugin.al.getAdmin(playerSender); + if (admin.getDiscordID() != null) + { + msg("Your Minecraft account is already linked to a Discord account.", ChatColor.RED); + return true; + } + + if (Discord.LINK_CODES.containsValue(admin)) + { + msg("Your linking code is " + ChatColor.GREEN + Discord.getCode(admin), ChatColor.AQUA); + } + else + { + String code = ""; + Random random = new Random(); + for (int i = 0; i < 5; i++) + { + code += random.nextInt(10); + } + Discord.LINK_CODES.put(code, admin); + msg("Your linking code is " + ChatColor.GREEN + code, ChatColor.AQUA); + } + return true; + } +} diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java new file mode 100644 index 000000000..b09b71dc8 --- /dev/null +++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_unlinkdiscord.java @@ -0,0 +1,35 @@ +package me.totalfreedom.totalfreedommod.command; + +import me.totalfreedom.totalfreedommod.admin.Admin; +import me.totalfreedom.totalfreedommod.rank.Rank; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +@CommandPermissions(level = Rank.SUPER_ADMIN, source = SourceType.ONLY_IN_GAME) +@CommandParameters(description = "Unlink your Discord account to your Minecraft account", usage = "/") +public class Command_unlinkdiscord extends FreedomCommand +{ + + @Override + public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole) + { + if (!plugin.dc.enabled) + { + msg("The Discord verification system is currently disabled.", ChatColor.RED); + return true; + } + + Admin admin = plugin.al.getAdmin(playerSender); + if (admin.getDiscordID() == null) + { + msg("Your Minecraft account is not linked to a Discord account.", ChatColor.RED); + return true; + } + admin.setDiscordID(null); + plugin.al.save(); + msg("Your Minecraft account has been successfully unlinked from the Discord account.", ChatColor.GREEN); + return true; + } +} diff --git a/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java new file mode 100644 index 000000000..79d250da5 --- /dev/null +++ b/src/main/java/me/totalfreedom/totalfreedommod/command/Command_verify.java @@ -0,0 +1,86 @@ +package me.totalfreedom.totalfreedommod.command; + +import me.totalfreedom.totalfreedommod.rank.Rank; +import me.totalfreedom.totalfreedommod.player.FPlayer; +import me.totalfreedom.totalfreedommod.admin.Admin; +import me.totalfreedom.totalfreedommod.util.FUtil; +import me.totalfreedom.totalfreedommod.config.ConfigEntry; +import me.totalfreedom.totalfreedommod.discord.Discord; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.ChatColor; +import java.util.Random; +import java.util.Date; +import net.pravian.aero.util.Ips; + +@CommandPermissions(level = Rank.IMPOSTOR, source = SourceType.ONLY_IN_GAME) +@CommandParameters(description = "Sends a verification code to the player, or the player can input the sent code.", usage = "/ [code]") +public class Command_verify extends FreedomCommand +{ + + @Override + public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole) + { + if (!plugin.dc.enabled) + { + msg("The discord verification system is currently disabled", ChatColor.RED); + return true; + } + + if (!plugin.al.isAdminImpostor(playerSender)) + { + msg("You are not an imposter, therefore you do not need to verify.", ChatColor.RED); + return true; + } + + Admin admin = plugin.al.getEntryByName(playerSender.getName()); + + if (admin.getDiscordID() == null) + { + msg("You do not have a discord account linked to your minecraft account, please verify the manual way.", ChatColor.RED); + return true; + } + + if (args.length < 1) + { + String code = ""; + Random random = new Random(); + for (int i = 0; i < 10; i++) + { + code += random.nextInt(10); + } + Discord.VERIFY_CODES.add(code); + Discord.bot.getUserById(admin.getDiscordID()).openPrivateChannel().complete().sendMessage("A user with the ip `" + Ips.getIp(playerSender) + "` has sent a verification request. Please run the following in-game command: `/verify " + code + "`").complete(); + msg("A verification code has been sent to your account, please copy the code and run /verify ", ChatColor.GREEN); + } + else + { + String code = args[0]; + if (!Discord.VERIFY_CODES.contains(code)) + { + msg("You have entered an invalid verification code", ChatColor.RED); + return true; + } + else + { + Discord.VERIFY_CODES.remove(code); + FUtil.bcastMsg(playerSender.getName() + " has verified themself via Discord!", ChatColor.GOLD); + FUtil.adminAction(ConfigEntry.SERVER_NAME.getString(), "Readding " + admin.getName() + " to the admin list", true); + admin.setName(playerSender.getName()); + admin.addIp(Ips.getIp(playerSender)); + admin.setActive(true); + admin.setLastLogin(new Date()); + plugin.al.save(); + plugin.al.updateTables(); + final FPlayer fPlayer = plugin.pl.getPlayer(playerSender); + if (fPlayer.getFreezeData().isFrozen()) + { + fPlayer.getFreezeData().setFrozen(false); + msg("You have been unfrozen."); + } + } + } + return true; + } +} diff --git a/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java b/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java index 01fa9ed8a..87eb8b3f1 100644 --- a/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java +++ b/src/main/java/me/totalfreedom/totalfreedommod/config/ConfigEntry.java @@ -38,6 +38,8 @@ public enum ConfigEntry SERVER_BAN_URL(String.class, "server.ban_url"), SERVER_PERMBAN_URL(String.class, "server.permban_url"), // + DISCORD_TOKEN(String.class, "discord.token"), + // ADMINLIST_CLEAN_THESHOLD_HOURS(Integer.class, "adminlist.clean_threshold_hours"), ADMINLIST_CONSOLE_IS_SENIOR(Boolean.class, "adminlist.console_is_senior"), // diff --git a/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java b/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java new file mode 100644 index 000000000..4b9751de0 --- /dev/null +++ b/src/main/java/me/totalfreedom/totalfreedommod/discord/Discord.java @@ -0,0 +1,85 @@ +package me.totalfreedom.totalfreedommod.discord; + +import com.google.common.base.Strings; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import javax.security.auth.login.LoginException; +import me.totalfreedom.totalfreedommod.FreedomService; +import me.totalfreedom.totalfreedommod.TotalFreedomMod; +import me.totalfreedom.totalfreedommod.admin.Admin; +import me.totalfreedom.totalfreedommod.config.ConfigEntry; +import me.totalfreedom.totalfreedommod.util.FLog; +import net.dv8tion.jda.core.AccountType; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDABuilder; + +public class Discord extends FreedomService +{ + public static HashMap LINK_CODES = new HashMap<>(); + public static List VERIFY_CODES = new ArrayList(); + public static JDA bot = null; + public Boolean enabled = false; + + public Discord(TotalFreedomMod plugin) + { + super(plugin); + } + + public void startBot() + { + enabled = !Strings.isNullOrEmpty(ConfigEntry.DISCORD_TOKEN.getString()); + if (!enabled) + { + return; + } + if (bot != null) + { + for (Object object : bot.getRegisteredListeners()) + { + bot.removeEventListener(object); + } + } + try + { + bot = new JDABuilder(AccountType.BOT).setToken(ConfigEntry.DISCORD_TOKEN.getString()).addEventListener(new MessageListener()).setAudioEnabled(false).setAutoReconnect(true).buildBlocking(); + FLog.info("Discord verification bot has successfully enabled!"); + } + catch (LoginException e) + { + FLog.warning("An invalid token for the discord verification bot, the bot will not enable."); + } + catch (IllegalArgumentException | InterruptedException e) + { + FLog.warning("Discord verification bot failed to start."); + } + } + + @Override + protected void onStart() + { + startBot(); + } + + public static String getCode(Admin admin) + { + for (String code : LINK_CODES.keySet()) + { + if (LINK_CODES.get(code).equals(admin)) + { + return code; + } + } + return null; + } + + @Override + protected void onStop() + { + if (bot != null) + { + bot.shutdown(); + } + FLog.info("Discord verification bot has successfully shutdown."); + } +} diff --git a/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java b/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java new file mode 100644 index 000000000..dfba67600 --- /dev/null +++ b/src/main/java/me/totalfreedom/totalfreedommod/discord/MessageListener.java @@ -0,0 +1,28 @@ +package me.totalfreedom.totalfreedommod.discord; + +import me.totalfreedom.totalfreedommod.admin.Admin; +import net.dv8tion.jda.core.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.core.hooks.ListenerAdapter; + +public class MessageListener extends ListenerAdapter +{ + public void onPrivateMessageReceived(PrivateMessageReceivedEvent event) + { + if (!event.getAuthor().getId().equals(Discord.bot.getSelfUser().getId())) + { + // Handle link code + if (event.getMessage().getContentRaw().matches("[0-9][0-9][0-9][0-9][0-9]")) + { + String code = event.getMessage().getContentRaw(); + if (Discord.LINK_CODES.get(code) != null) + { + Admin admin = Discord.LINK_CODES.get(code); + admin.setDiscordID(event.getMessage().getAuthor().getId()); + Discord.LINK_CODES.remove(code); + event.getChannel().sendMessage("Link successful. Now this Discord account is linked with the Minecraft account `" + admin.getName() + "`.\n " + + "Now when you are an impostor on the server, you may use `/verify` to verify.").complete(); + } + } + } + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8c0bddb0a..d5df06d96 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -27,6 +27,11 @@ server: # URL players should appeal for permanent bans at permban_url: http://bit.ly/TF_PermBan +# Discord +discord: + # If you do not have a token, make a bot account and get one at https://discordapp.com/developers/applications/me + token: '' + # Admin list adminlist: