WIP
This commit is contained in:
parent
e0406a8f65
commit
99f5a817bd
|
@ -4,7 +4,8 @@ import eu.oskar3123.spigot2fa.command.TFACommand;
|
|||
import eu.oskar3123.spigot2fa.config.Config;
|
||||
import eu.oskar3123.spigot2fa.config.ConfigHandler;
|
||||
import eu.oskar3123.spigot2fa.handler.TFAHandler;
|
||||
import eu.oskar3123.spigot2fa.listener.JoinQuitListener;
|
||||
import eu.oskar3123.spigot2fa.listener.AuthListener;
|
||||
import eu.oskar3123.spigot2fa.listener.MapListener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
|
@ -41,7 +42,8 @@ public class Main extends JavaPlugin
|
|||
private void registerListeners()
|
||||
{
|
||||
PluginManager pm = this.getServer().getPluginManager();
|
||||
pm.registerEvents(new JoinQuitListener(this), this);
|
||||
pm.registerEvents(new AuthListener(this), this);
|
||||
pm.registerEvents(new MapListener(this), this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,18 +2,28 @@ package eu.oskar3123.spigot2fa.command;
|
|||
|
||||
import eu.oskar3123.spigot2fa.Main;
|
||||
import eu.oskar3123.spigot2fa.handler.TFAHandler;
|
||||
import eu.oskar3123.spigot2fa.tfa.TFA;
|
||||
import eu.oskar3123.spigot2fa.util.PlayerUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.StringUtil;
|
||||
|
||||
public class TFACommand implements CommandExecutor
|
||||
import java.util.*;
|
||||
|
||||
public class TFACommand implements CommandExecutor, TabCompleter
|
||||
{
|
||||
|
||||
private Main plugin;
|
||||
private TFAHandler th;
|
||||
private final Map<String, String[]> TAB_COMPLETE_MAP = new HashMap<>();
|
||||
{
|
||||
TAB_COMPLETE_MAP.put("", new String[]{"add", "remove", "<code>"});
|
||||
TAB_COMPLETE_MAP.put(":remove", new String[]{"[player]"});
|
||||
}
|
||||
|
||||
public TFACommand(Main plugin)
|
||||
{
|
||||
|
@ -25,29 +35,123 @@ public class TFACommand implements CommandExecutor
|
|||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
{
|
||||
Player player = (Player) sender;
|
||||
if (!th.isInProcess(player.getUniqueId()))
|
||||
if (args.length >= 1 && args[0].equalsIgnoreCase("remove"))
|
||||
{
|
||||
th.startCreating(player);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
String secret = th.getKey(player.getUniqueId());
|
||||
String code = TFA.getTOTPCode(secret);
|
||||
String pCode = StringUtils.join(args);
|
||||
if (th.matchCode(code, pCode))
|
||||
if (!player.hasPermission("2fa.remove"))
|
||||
{
|
||||
th.creatingSuccess(player);
|
||||
player.sendMessage("Successfully activated 2FA");
|
||||
player.sendMessage("You don't have permission to do that");
|
||||
return true;
|
||||
}
|
||||
if (args.length >= 2 && player.hasPermission("2fa.remove.other"))
|
||||
{
|
||||
OfflinePlayer otherPlayer = PlayerUtils.getOfflinePlayer(args[1]);
|
||||
if (otherPlayer == null)
|
||||
{
|
||||
player.sendMessage("Could not find player \"" + args[1] + "\".");
|
||||
return true;
|
||||
}
|
||||
if (th.hasEnabled2FA(otherPlayer.getUniqueId()))
|
||||
{
|
||||
th.remove2FA(otherPlayer.getUniqueId());
|
||||
player.sendMessage("Removed two-factor authentication for " + otherPlayer.getName() + ".");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.sendMessage(otherPlayer.getName() + " does not have two-factor authentication enabled.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (th.hasEnabled2FA(player.getUniqueId()))
|
||||
{
|
||||
th.remove2FA(player.getUniqueId());
|
||||
player.sendMessage("Removed two-factor authentication.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
th.creatingFailed(player);
|
||||
player.sendMessage("That code is incorrect, aborting");
|
||||
player.sendMessage("You don't have two-factor authentication enabled.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (args.length >= 1 && args[0].equalsIgnoreCase("add"))
|
||||
{
|
||||
if (!player.hasPermission("2fa.activate"))
|
||||
{
|
||||
player.sendMessage("You don't have permission to do that");
|
||||
return true;
|
||||
}
|
||||
if (th.hasEnabled2FA(player.getUniqueId()))
|
||||
{
|
||||
player.sendMessage("You have already enabled two-factor authentication.");
|
||||
return true;
|
||||
}
|
||||
if (!th.isInProcess(player.getUniqueId()))
|
||||
{
|
||||
boolean canStart = th.startCreating(player);
|
||||
if (!canStart)
|
||||
{
|
||||
player.sendMessage("You can't hold anything when starting the process.");
|
||||
return true;
|
||||
}
|
||||
player.sendMessage("Scan the barcode or enter the secret manually in your 2FA app.");
|
||||
player.sendMessage("Use /2fa <code> to verify the authenticator.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
String secret = th.getKey(player.getUniqueId());
|
||||
String pCode = StringUtils.join(args);
|
||||
if (th.matchCode(secret, pCode))
|
||||
{
|
||||
th.creatingSuccess(player);
|
||||
player.sendMessage("Successfully activated two-factor authentication.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
th.creatingFailed(player);
|
||||
player.sendMessage("That code is incorrect, aborting.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (th.isInProcess(player.getUniqueId()))
|
||||
{
|
||||
player.sendMessage("Confirm the activation by typing /2fa <code>.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.sendMessage("Usage: " + command.getUsage().replace("<command>", label));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args)
|
||||
{
|
||||
if (args.length < 1)
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
StringBuilder search = new StringBuilder();
|
||||
for (int i = 0; i < args.length - 1; i++)
|
||||
{
|
||||
search.append(":").append(args[i]);
|
||||
}
|
||||
if (!TAB_COMPLETE_MAP.containsKey(search.toString()))
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
String[] commands = TAB_COMPLETE_MAP.get(search.toString());
|
||||
final List<String> completions = new ArrayList<>();
|
||||
StringUtil.copyPartialMatches(args[args.length - 1], Arrays.asList(commands), completions);
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.oskar3123.spigot2fa.config;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
@ -55,18 +56,40 @@ public class ConfigHandler
|
|||
}
|
||||
|
||||
public void saveConfig(Config config)
|
||||
{
|
||||
saveConfig(config, false);
|
||||
}
|
||||
|
||||
public void saveConfig(Config config, boolean async)
|
||||
{
|
||||
if (config.fileConfig == null || config.file == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
if (async)
|
||||
{
|
||||
getConfig(config).save(config.file);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () ->
|
||||
{
|
||||
try
|
||||
{
|
||||
getConfig(config).save(config.file);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
plugin.getLogger().log(Level.SEVERE, "Could not save config to " + config.file, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException ex)
|
||||
else
|
||||
{
|
||||
plugin.getLogger().log(Level.SEVERE, "Could not save config to " + config.file, ex);
|
||||
try
|
||||
{
|
||||
getConfig(config).save(config.file);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
plugin.getLogger().log(Level.SEVERE, "Could not save config to " + config.file, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,6 +103,7 @@ public class ConfigHandler
|
|||
{
|
||||
plugin.saveResource(config.name + ".yml", false);
|
||||
}
|
||||
reloadConfig(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.bukkit.inventory.meta.MapMeta;
|
|||
import org.bukkit.map.MapView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
@ -27,21 +28,67 @@ public class TFAHandler
|
|||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public boolean shouldBypassCode(Player player)
|
||||
{
|
||||
UUID uuid = player.getUniqueId();
|
||||
String ip = player.getAddress().getAddress().getHostAddress();
|
||||
if (!hasEnabled2FA(uuid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
long now = new Date().getTime();
|
||||
long sessionTimeInMs = plugin.configHandler.getConfig(plugin.config).getLong("2fa.sessiontime") * 60000L;
|
||||
Configuration players = plugin.configHandler.getConfig(plugin.players);
|
||||
long last = players.getLong(uuid.toString() + ".lastlogin");
|
||||
String lastIp = players.getString(uuid.toString() + ".lastip");
|
||||
return last >= now - sessionTimeInMs && ip.equalsIgnoreCase(lastIp);
|
||||
}
|
||||
|
||||
public void setLastLogin(Player player, Long time)
|
||||
{
|
||||
UUID uuid = player.getUniqueId();
|
||||
String ip = player.getAddress().getAddress().getHostAddress();
|
||||
if (!hasEnabled2FA(uuid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
long now;
|
||||
if (time == null)
|
||||
{
|
||||
now = new Date().getTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
now = time;
|
||||
}
|
||||
Configuration players = plugin.configHandler.getConfig(plugin.players);
|
||||
players.set(uuid.toString() + ".lastlogin", now);
|
||||
players.set(uuid.toString() + ".lastip", ip);
|
||||
plugin.configHandler.saveConfig(plugin.players, true);
|
||||
}
|
||||
|
||||
public String formatSecret(String secret)
|
||||
{
|
||||
return secret.toLowerCase().replaceAll("(.{4})(?=.{4})", "$1 ");
|
||||
}
|
||||
|
||||
public void remove2FA(UUID uuid)
|
||||
{
|
||||
plugin.configHandler.getConfig(plugin.players).set(uuid.toString(), null);
|
||||
plugin.configHandler.saveConfig(plugin.players, true);
|
||||
}
|
||||
|
||||
public boolean hasEnabled2FA(UUID uuid)
|
||||
{
|
||||
return plugin.configHandler.getConfig(plugin.players).isString(uuid.toString());
|
||||
return plugin.configHandler.getConfig(plugin.players).isString(uuid.toString() + ".secret");
|
||||
}
|
||||
|
||||
public void creatingSuccess(Player player)
|
||||
{
|
||||
String secret = remove(player.getUniqueId());
|
||||
plugin.configHandler.getConfig(plugin.players).set(player.getUniqueId().toString(), secret);
|
||||
plugin.configHandler.saveConfig(plugin.players);
|
||||
player.getInventory().setItemInMainHand(new ItemStack(Material.AIR));
|
||||
plugin.configHandler.getConfig(plugin.players).set(player.getUniqueId().toString() + ".secret", secret);
|
||||
plugin.configHandler.saveConfig(plugin.players, true);
|
||||
}
|
||||
|
||||
public void creatingFailed(Player player)
|
||||
|
@ -49,15 +96,22 @@ public class TFAHandler
|
|||
remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
public boolean matchCode(String code1, String code2)
|
||||
public boolean matchCode(String secret, String code)
|
||||
{
|
||||
return code1.equalsIgnoreCase(code2);
|
||||
String[] actualCodes = TFA.getTOTPCodes(secret);
|
||||
for (String actualCode : actualCodes)
|
||||
{
|
||||
if (actualCode.equalsIgnoreCase(code))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean matchCode(Player player, String code)
|
||||
{
|
||||
String actualCode = TFA.getTOTPCode(getKey(player.getUniqueId()));
|
||||
return matchCode(actualCode, code);
|
||||
return matchCode(getKey(player.getUniqueId()), code);
|
||||
}
|
||||
|
||||
private String remove(UUID uuid)
|
||||
|
@ -65,33 +119,42 @@ public class TFAHandler
|
|||
return isInProcess.remove(uuid);
|
||||
}
|
||||
|
||||
public String startCreating(Player player)
|
||||
public boolean startCreating(Player player)
|
||||
{
|
||||
String key = TFA.getRandomSecretKey();
|
||||
isInProcess.put(player.getUniqueId(), key);
|
||||
showQRCode(player, key);
|
||||
return key;
|
||||
boolean couldShow = showQRCode(player, key);
|
||||
if (couldShow)
|
||||
{
|
||||
isInProcess.put(player.getUniqueId(), key);
|
||||
}
|
||||
return couldShow;
|
||||
}
|
||||
|
||||
private void showQRCode(Player player, String secret)
|
||||
private boolean showQRCode(Player player, String secret)
|
||||
{
|
||||
ItemStack inHand = player.getInventory().getItemInMainHand();
|
||||
if (inHand != null && inHand.getType() != Material.AIR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
ItemStack map = new ItemStack(Material.FILLED_MAP);
|
||||
MapView view = Bukkit.createMap(player.getWorld());
|
||||
view.getRenderers().clear();
|
||||
view.addRenderer(new QRMapRenderer(secret, player));
|
||||
view.addRenderer(new QRMapRenderer(plugin, formatSecret(secret), player));
|
||||
MapMeta mapMeta = (MapMeta) map.getItemMeta();
|
||||
mapMeta.setMapId(view.getId());
|
||||
map.setItemMeta(mapMeta);
|
||||
player.getInventory().setItemInMainHand(map);
|
||||
player.sendMap(view);
|
||||
player.sendMessage("Secret Key: " + secret);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
player.sendMessage("Failed to generate qr code");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +170,16 @@ public class TFAHandler
|
|||
return isInProcess.get(uuid);
|
||||
}
|
||||
Configuration players = plugin.configHandler.getConfig(plugin.players);
|
||||
return players.getString(uuid.toString());
|
||||
return players.getString(uuid.toString() + ".secret");
|
||||
}
|
||||
|
||||
public void stopCreating(Player player)
|
||||
{
|
||||
if (!isInProcess(player.getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
isInProcess.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package eu.oskar3123.spigot2fa.listener;
|
||||
|
||||
import eu.oskar3123.spigot2fa.Main;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class AuthListener implements Listener
|
||||
{
|
||||
|
||||
private class WaitingInfo
|
||||
{
|
||||
private BukkitTask kickTask;
|
||||
private BukkitTask teleportTask;
|
||||
|
||||
private WaitingInfo(BukkitTask kickTask, BukkitTask teleportTask)
|
||||
{
|
||||
this.kickTask = kickTask;
|
||||
this.teleportTask = teleportTask;
|
||||
}
|
||||
|
||||
private void cancel(Player player)
|
||||
{
|
||||
this.kickTask.cancel();
|
||||
this.teleportTask.cancel();
|
||||
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||
}
|
||||
}
|
||||
|
||||
private Main plugin;
|
||||
private Map<UUID, WaitingInfo> waitingForCode = new HashMap<>();
|
||||
|
||||
public AuthListener(Main plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event)
|
||||
{
|
||||
if (plugin.tfaHandler.shouldBypassCode(event.getPlayer()))
|
||||
{
|
||||
event.getPlayer().sendMessage("bypassed 2fa check");
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
BukkitTask task = Bukkit.getScheduler().runTaskLater(plugin, () ->
|
||||
{
|
||||
waitingForCode.remove(player.getUniqueId());
|
||||
player.kickPlayer("You did not enter the 2FA code in time.");
|
||||
}, 800L);
|
||||
// 800 ticks == 40 secs
|
||||
final Location loginLocation = player.getLocation().clone();
|
||||
BukkitTask tpTask = Bukkit.getScheduler().runTaskTimer(plugin, () ->
|
||||
{
|
||||
player.teleport(loginLocation);
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 45, 0, false, false), true);
|
||||
}, 0L, 20L);
|
||||
waitingForCode.put(player.getUniqueId(), new WaitingInfo(task, tpTask));
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> player.sendMessage("Please enter your 2FA code in the chat."), 1L);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void chat(AsyncPlayerChatEvent event)
|
||||
{
|
||||
if (!waitingForCode.containsKey(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
boolean correct = plugin.tfaHandler.matchCode(event.getPlayer(), event.getMessage());
|
||||
event.setCancelled(true);
|
||||
if (!correct)
|
||||
{
|
||||
event.getPlayer().sendMessage("Incorrect code, try again.");
|
||||
}
|
||||
else
|
||||
{
|
||||
waitingForCode.remove(event.getPlayer().getUniqueId()).cancel(event.getPlayer());
|
||||
plugin.tfaHandler.setLastLogin(event.getPlayer(), null);
|
||||
event.getPlayer().sendMessage("You have been authorized.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void command(PlayerCommandPreprocessEvent event)
|
||||
{
|
||||
if (!waitingForCode.containsKey(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
event.getPlayer().sendMessage("You have to authorize first.");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package eu.oskar3123.spigot2fa.listener;
|
||||
|
||||
import eu.oskar3123.spigot2fa.Main;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class JoinQuitListener implements Listener
|
||||
{
|
||||
|
||||
private Main plugin;
|
||||
private Set<UUID> waitingForCode = new HashSet<>();
|
||||
|
||||
public JoinQuitListener(Main plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event)
|
||||
{
|
||||
boolean enabled = plugin.tfaHandler.hasEnabled2FA(event.getPlayer().getUniqueId());
|
||||
if (!enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.getPlayer().sendMessage("Enter 2FA code");
|
||||
waitingForCode.add(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void chat(AsyncPlayerChatEvent event)
|
||||
{
|
||||
if (!waitingForCode.contains(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
boolean correct = plugin.tfaHandler.matchCode(event.getPlayer(), event.getMessage());
|
||||
waitingForCode.remove(event.getPlayer().getUniqueId());
|
||||
event.setCancelled(true);
|
||||
if (!correct)
|
||||
{
|
||||
final Player player = event.getPlayer();
|
||||
Bukkit.getScheduler().runTask(plugin, () -> player.kickPlayer("Wrong code!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
event.getPlayer().sendMessage("Logged in");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package eu.oskar3123.spigot2fa.listener;
|
||||
|
||||
import eu.oskar3123.spigot2fa.Main;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class MapListener implements Listener
|
||||
{
|
||||
|
||||
private Main plugin;
|
||||
|
||||
public MapListener(Main plugin)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void quit(PlayerQuitEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
plugin.tfaHandler.stopCreating(event.getPlayer());
|
||||
event.getPlayer().getInventory().setItemInMainHand(new ItemStack(Material.AIR));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void drop(PlayerDropItemEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (event.getItemDrop().getItemStack().getType() != Material.FILLED_MAP)
|
||||
{
|
||||
return;
|
||||
}
|
||||
plugin.tfaHandler.stopCreating(event.getPlayer());
|
||||
event.getPlayer().sendMessage("Aborted adding two-factor authentication.");
|
||||
event.getItemDrop().remove();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void slot(PlayerItemHeldEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void open(InventoryOpenEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void open(InventoryClickEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getWhoClicked().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void open(InventoryCreativeEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getWhoClicked().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void open(InventoryDragEvent event)
|
||||
{
|
||||
if (!plugin.tfaHandler.isInProcess(event.getWhoClicked().getUniqueId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package eu.oskar3123.spigot2fa.map;
|
||||
|
||||
import eu.oskar3123.spigot2fa.tfa.TFA;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.MapMeta;
|
||||
import org.bukkit.map.MapView;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class CreateMapRunnable implements Runnable
|
||||
{
|
||||
|
||||
private Player player;
|
||||
|
||||
public CreateMapRunnable(Player player)
|
||||
{
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
ItemStack map = new ItemStack(Material.FILLED_MAP);
|
||||
MapView view = Bukkit.createMap(player.getWorld());
|
||||
view.getRenderers().clear();
|
||||
String secret = TFA.getRandomSecretKey();
|
||||
view.addRenderer(new QRMapRenderer(secret, player));
|
||||
MapMeta mapMeta = (MapMeta) map.getItemMeta();
|
||||
mapMeta.setMapId(view.getId());
|
||||
map.setItemMeta(mapMeta);
|
||||
player.getInventory().setItemInMainHand(map);
|
||||
player.sendMap(view);
|
||||
player.sendMessage("Secret Key: " + secret);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
player.sendMessage("Failed to generate qr code");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -25,10 +25,14 @@ public class QRMapRenderer extends MapRenderer
|
|||
{
|
||||
this.plugin = plugin;
|
||||
this.uuid = player.getUniqueId();
|
||||
String[] formattedSecretKey = secretKey .replaceAll("((?:.{4} ){4})", "$1;").split(";");
|
||||
String[] formattedSecretKey = secretKey.replaceAll("((?:.{4} ){4})", "$1;").split(";");
|
||||
this.line1 = formattedSecretKey[0].trim();
|
||||
this.line2 = formattedSecretKey[1].trim();
|
||||
initImage(TFA.getGoogleAuthenticatorBarCode(secretKey, "Mineworlds", player.getName() + " (" + player.getUniqueId().toString() + ")"));
|
||||
String issuer = plugin.configHandler.getConfig(plugin.config).getString("2fa.issuer");
|
||||
String account = plugin.configHandler.getConfig(plugin.config).getString("2fa.account")
|
||||
.replace("{NAME}", player.getName())
|
||||
.replace("{UUID}", player.getUniqueId().toString());
|
||||
initImage(TFA.getGoogleAuthenticatorBarCode(secretKey, issuer, account));
|
||||
}
|
||||
|
||||
private void initImage(String qrValue) throws IOException
|
||||
|
|
|
@ -22,7 +22,7 @@ public class TFA
|
|||
return secretKey.toUpperCase();
|
||||
}
|
||||
|
||||
public static String getTOTPCode(String secretKey)
|
||||
public static String[] getTOTPCodes(String secretKey)
|
||||
{
|
||||
String normalizedBase32Key = secretKey.replace(" ", "").toUpperCase();
|
||||
Base32 base32 = new Base32();
|
||||
|
@ -30,7 +30,11 @@ public class TFA
|
|||
String hexKey = Hex.encodeHexString(bytes);
|
||||
long time = (System.currentTimeMillis() / 1000) / 30;
|
||||
String hexTime = Long.toHexString(time);
|
||||
return TOTP.generateTOTP(hexKey, hexTime, "6");
|
||||
String code1 = TOTP.generateTOTP(hexKey, hexTime, "6");
|
||||
time = time - 1;
|
||||
hexTime = Long.toHexString(time);
|
||||
String code2 = TOTP.generateTOTP(hexKey, hexTime, "6");
|
||||
return new String[] {code1, code2};
|
||||
}
|
||||
|
||||
public static String getGoogleAuthenticatorBarCode(String secretKey, String issuer, String account)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package eu.oskar3123.spigot2fa.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
public class PlayerUtils
|
||||
{
|
||||
|
||||
public static OfflinePlayer getOfflinePlayer(String name)
|
||||
{
|
||||
for (OfflinePlayer ply : Bukkit.getOfflinePlayers())
|
||||
{
|
||||
if (ply == null || ply.getName() == null || ply.getName().isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ply.getName().toLowerCase().startsWith(name.toLowerCase()))
|
||||
{
|
||||
return ply;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
2fa:
|
||||
issuer: 'Mineworlds'
|
||||
account: '{NAME}'
|
||||
# session time in minutes
|
||||
sessiontime: 1440
|
||||
|
|
|
@ -5,3 +5,5 @@ authors: [oskar3123]
|
|||
main: eu.oskar3123.spigot2fa.Main
|
||||
commands:
|
||||
2fa:
|
||||
usage: '/<command> add/remove/<code>'
|
||||
description: 'Two-factor authorization command'
|
||||
|
|
Loading…
Reference in New Issue