diff --git a/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorAuth.java b/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorAuth.java index 06a982520..4b3245cee 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorAuth.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorAuth.java @@ -63,20 +63,74 @@ public class TwoFactorAuth extends MiniClientPlugin @Override public void addCommands() { - // TODO: remove this when we start enforcing 2FA addCommand(new CommandBase(this, Rank.MAPDEV, "2fa", "tfa") { @Override public void Execute(Player caller, String[] args) { - TwoFactorData data = Get(caller); - if (data.getSecretKey().isPresent()) + if (args.length < 1 || !args[0].toLowerCase().equals("reset")) { - caller.sendMessage(F.main("2FA", "You already have 2FA enabled.")); + if (_clientManager.Get(caller).GetRank(true).has(Rank.ADMIN)) + { + caller.sendMessage(F.main("2FA", "Usage: /2fa reset [player]")); + } + else + { + caller.sendMessage(F.main("2FA", "Usage: /2fa reset")); + } return; } - setup2FA(caller); + if (args.length == 1) // Resetting their own 2FA + { + caller.sendMessage(F.main("2FA", "Resetting 2FA..")); + _repository.deletePlayerData(_clientManager.getAccountId(caller)).whenComplete(BukkitFuture.complete((__, err) -> + { + if (err != null) + { + caller.sendMessage(F.main("2FA", "Something went wrong. Have you already reset 2FA?")); + err.printStackTrace(); + } + else + { + caller.sendMessage(F.main("2FA", "Successfully reset.")); + setup2FA(caller); + } + })); + return; + } + + if (!_clientManager.Get(caller).GetRank(true).has(Rank.ADMIN)) + { + caller.sendMessage(F.main("2FA", "Only admins can reset 2FA for other players")); + return; + } + + _clientManager.getOrLoadClient(args[1], client -> + { + if (client == null) + { + caller.sendMessage(F.main("2FA", "Couldn't find player with the name \"" + args[1] + "\"")); + return; + } + + caller.sendMessage(F.main("2FA", "Resetting 2FA for \"" + client.getName() + "\"")); + _repository.deletePlayerData(client.getAccountId()).whenComplete(BukkitFuture.complete((__, err) -> + { + if (err != null) + { + caller.sendMessage(F.main("2FA", "Something went wrong. Maybe they've already reset 2FA?")); + } + else + { + caller.sendMessage(F.main("2FA", "Successfully reset.")); + if (client.GetPlayer() != null) + { + setup2FA(client.GetPlayer()); + } + } + })); + }); } }); } @@ -125,7 +179,7 @@ public class TwoFactorAuth extends MiniClientPlugin TwoFactorData data = Get(player); - if (data.getLastLoginIp().isPresent() && player.getAddress().getAddress().toString().substring(1).equals(data.getLastLoginIp().get())) + if (data.getLastLoginIp().isPresent() && player.getAddress().getAddress().toString().substring(1).equals(data.getLastLoginIp().get()) || _clientManager.Get(player).GetRank(true) == Rank.SUPPORT) { player.sendMessage(F.main("2FA", "Authenticated")); return; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorRepository.java index 20d5810b0..b2afff3c0 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/twofactor/TwoFactorRepository.java @@ -19,7 +19,9 @@ import mineplex.core.account.ILoginProcessor; public class TwoFactorRepository { private static final String INSERT_SECRET_KEY = "INSERT INTO twofactor (accountId,secretKey) VALUES (?,?);"; + private static final String DELETE_SECRET_KEY = "DELETE FROM twofactor WHERE accountId=?;"; private static final String INSERT_LOGIN = "INSERT INTO twofactor_history (accountId,ip,loginTime) VALUES (?,?,NOW());"; + private static final String DELETE_RECENT_LOGINS = "DELETE FROM twofactor_history WHERE accountId=? AND loginTime >= DATE_SUB(NOW(), INTERVAL 1 DAY);"; private final CoreClientManager _clientManager = Managers.require(CoreClientManager.class); private final DataSource _dataSource; @@ -121,4 +123,25 @@ public class TwoFactorRepository } }); } + + public CompletableFuture deletePlayerData(int accountId) + { + return CompletableFuture.runAsync(() -> + { + try (Connection connection = _dataSource.getConnection()) + { + PreparedStatement statement = connection.prepareStatement(DELETE_SECRET_KEY); + statement.setInt(1, accountId); + statement.executeUpdate(); + + statement = connection.prepareStatement(DELETE_RECENT_LOGINS); + statement.setInt(1, accountId); + statement.executeUpdate(); + } + catch (SQLException e) + { + throw new CompletionException(e); + } + }); + } }