Merge remote-tracking branch 'refs/remotes/origin/develop' into feature/gem-hunters
This commit is contained in:
commit
64026f81ff
@ -50,6 +50,16 @@
|
||||
<artifactId>xz</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.warrenstrange</groupId>
|
||||
<artifactId>googleauth</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -0,0 +1,320 @@
|
||||
package mineplex.core.twofactor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.map.MapRenderer;
|
||||
import org.bukkit.map.MapView;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
import com.warrenstrange.googleauth.GoogleAuthenticator;
|
||||
|
||||
import mineplex.core.Managers;
|
||||
import mineplex.core.MiniClientPlugin;
|
||||
import mineplex.core.ReflectivelyCreateMiniPlugin;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.command.CommandBase;
|
||||
import mineplex.core.common.Rank;
|
||||
import mineplex.core.common.util.BukkitFuture;
|
||||
import mineplex.core.common.util.F;
|
||||
import mineplex.core.recharge.Recharge;
|
||||
import mineplex.serverdata.database.DBPool;
|
||||
|
||||
@ReflectivelyCreateMiniPlugin
|
||||
public class TwoFactorAuth extends MiniClientPlugin<TwoFactorData>
|
||||
{
|
||||
private static final String TFA_SETUP = "twofactor:setup";
|
||||
private static final String TFA_AUTHENTICATING = "twofactor:authenticating";
|
||||
|
||||
private static final GoogleAuthenticator authenticator = new GoogleAuthenticator();
|
||||
private final CoreClientManager _clientManager = Managers.require(CoreClientManager.class);
|
||||
private final TwoFactorRepository _repository = new TwoFactorRepository(DBPool.getAccount());
|
||||
|
||||
public TwoFactorAuth()
|
||||
{
|
||||
super("Two-factor Authentication");
|
||||
_clientManager.addStoredProcedureLoginProcessor(
|
||||
_repository.buildSecretKeyLoginProcessor((uuid, secretKey) -> Get(uuid).setSecretKey(secretKey))
|
||||
);
|
||||
_clientManager.addStoredProcedureLoginProcessor(
|
||||
_repository.buildLastIpLoginProcessor((uuid, ip) -> Get(uuid).setLastLoginIp(ip))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCommands()
|
||||
{
|
||||
// TODO: remove this when we start enforcing 2FA
|
||||
addCommand(new CommandBase<TwoFactorAuth>(this, Rank.MAPDEV, "2fa", "tfa")
|
||||
{
|
||||
@Override
|
||||
public void Execute(Player caller, String[] args)
|
||||
{
|
||||
TwoFactorData data = Get(caller);
|
||||
if (data.getSecretKey().isPresent())
|
||||
{
|
||||
caller.sendMessage(F.main("2FA", "You already have 2FA enabled."));
|
||||
return;
|
||||
}
|
||||
|
||||
setup2FA(caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setup2FA(Player player)
|
||||
{
|
||||
String secret = authenticator.createCredentials().getKey();
|
||||
|
||||
MapView view = Bukkit.createMap(player.getWorld());
|
||||
for (MapRenderer renderer : view.getRenderers())
|
||||
{
|
||||
view.removeRenderer(renderer);
|
||||
}
|
||||
view.addRenderer(new TwoFactorMapRenderer(player, secret));
|
||||
|
||||
ItemStack stack = new ItemStack(Material.MAP);
|
||||
stack.setDurability(view.getId());
|
||||
|
||||
// Find first free hotbar slot
|
||||
int slot = 0;
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
if (player.getInventory().getItem(i) == null)
|
||||
{
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
player.getInventory().setHeldItemSlot(slot);
|
||||
player.getInventory().setItemInHand(stack);
|
||||
|
||||
player.setMetadata(TFA_SETUP, new FixedMetadataValue(_plugin, secret));
|
||||
player.sendMessage(F.main("2FA", "Setting up two-factor authentication."));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
|
||||
TwoFactorData data = Get(player);
|
||||
|
||||
if (data.getLastLoginIp().isPresent() && player.getAddress().getAddress().toString().substring(1).equals(data.getLastLoginIp().get()))
|
||||
{
|
||||
player.sendMessage(F.main("2FA", "Authenticated"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getSecretKey().isPresent())
|
||||
{
|
||||
// Hooray 2FA
|
||||
player.sendMessage(F.main("2FA", "Please enter your two-factor auth code"));
|
||||
player.setMetadata(TFA_AUTHENTICATING, new FixedMetadataValue(_plugin, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2FA not set up yet. TODO: enforce this at a later date.
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP))
|
||||
{
|
||||
player.setItemInHand(null);
|
||||
player.removeMetadata(TFA_SETUP, _plugin);
|
||||
}
|
||||
player.removeMetadata(TFA_AUTHENTICATING, _plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onChat(AsyncPlayerChatEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
|
||||
String secret = null;
|
||||
if (player.hasMetadata(TFA_SETUP))
|
||||
{
|
||||
secret = player.getMetadata(TFA_SETUP).get(0).asString();
|
||||
}
|
||||
else if (player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
secret = Get(player).getSecretKey().get();
|
||||
}
|
||||
|
||||
if (secret == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Hooray 2FA - let's see if their message matches their auth code
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
int code;
|
||||
try
|
||||
{
|
||||
code = Integer.parseInt(event.getMessage());
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
player.sendMessage(F.main("2FA", "Invalid authentication code (not a number)."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!authenticator.authorize(secret, code))
|
||||
{
|
||||
player.sendMessage(F.main("2FA", "Invalid authentication code."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Success!
|
||||
|
||||
player.sendMessage(F.main("2FA", "Authorized for 24 hours."));
|
||||
|
||||
if (player.hasMetadata(TFA_SETUP))
|
||||
{
|
||||
// Remove setup map + save secret
|
||||
player.setItemInHand(null);
|
||||
Get(player).setSecretKey(secret);
|
||||
|
||||
player.sendMessage(F.main("2FA", "Saving secret.."));
|
||||
_repository.saveSecret(player, secret).whenComplete(BukkitFuture.complete((v, throwable) ->
|
||||
{
|
||||
if (!player.isOnline())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (throwable != null)
|
||||
{
|
||||
Get(player).setSecretKey(null);
|
||||
player.sendMessage(F.main("2FA", "Something went wrong. Please try again in a moment."));
|
||||
}
|
||||
else
|
||||
{
|
||||
player.sendMessage(F.main("2FA", "Secret key saved."));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
_repository.saveLogin(player, player.getAddress().getAddress().toString().substring(1));
|
||||
|
||||
player.removeMetadata(TFA_SETUP, _plugin);
|
||||
player.removeMetadata(TFA_AUTHENTICATING, _plugin);
|
||||
}
|
||||
|
||||
// Cancel relevant events
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onChangeHeldItem(PlayerItemHeldEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onClick(InventoryClickEvent event)
|
||||
{
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onDrag(InventoryDragEvent event)
|
||||
{
|
||||
Player player = (Player) event.getWhoClicked();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onDrop(PlayerDropItemEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onInteract(PlayerInteractEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onInteractWithEntity(PlayerInteractEntityEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onCommand(PlayerCommandPreprocessEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
event.setMessage("/");
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onMove(PlayerMoveEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
if (player.hasMetadata(TFA_SETUP) || player.hasMetadata(TFA_AUTHENTICATING))
|
||||
{
|
||||
if (Recharge.Instance.use(player, "two-factor message cooldown", 3000L, false, false))
|
||||
{
|
||||
player.sendMessage(F.main("2FA", "Please enter your two-factor auth code"));
|
||||
}
|
||||
event.getTo().setX(event.getFrom().getX());
|
||||
event.getTo().setZ(event.getFrom().getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TwoFactorData addPlayer(UUID uuid)
|
||||
{
|
||||
return new TwoFactorData();
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package mineplex.core.twofactor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class TwoFactorData
|
||||
{
|
||||
private String _secretKey;
|
||||
private String _lastIp;
|
||||
|
||||
public Optional<String> getSecretKey()
|
||||
{
|
||||
return Optional.ofNullable(_secretKey);
|
||||
}
|
||||
|
||||
public Optional<String> getLastLoginIp()
|
||||
{
|
||||
return Optional.ofNullable(_lastIp);
|
||||
}
|
||||
|
||||
public void setSecretKey(String secretKey)
|
||||
{
|
||||
_secretKey = secretKey;
|
||||
}
|
||||
|
||||
public void setLastLoginIp(String lastIp)
|
||||
{
|
||||
_lastIp = lastIp;
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package mineplex.core.twofactor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.map.MapCanvas;
|
||||
import org.bukkit.map.MapFont;
|
||||
import org.bukkit.map.MapRenderer;
|
||||
import org.bukkit.map.MapView;
|
||||
import org.bukkit.map.MinecraftFont;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.qrcode.QRCodeWriter;
|
||||
|
||||
public class TwoFactorMapRenderer extends MapRenderer
|
||||
{
|
||||
private static final String SETUP_TEXT =
|
||||
"\u00A7100;Two-factor Auth Setup\n\n" +
|
||||
"\u00A744;1. Use your device to\n" +
|
||||
"scan the QR code, or\n" +
|
||||
"enter your \u00A716;secret code:\n" +
|
||||
"\u00A728;%s\n\n" +
|
||||
"\u00A744;2. Type the\n" +
|
||||
"code from\n" +
|
||||
"the app\n" +
|
||||
"in chat.";
|
||||
private static final MapFont FONT = MinecraftFont.Font;
|
||||
private static final byte QR_COLOR = (byte)116; // Black
|
||||
private static final QRCodeWriter writer = new QRCodeWriter();
|
||||
|
||||
private final Player _player;
|
||||
private final byte[][] contents = new byte[128][128];
|
||||
|
||||
public TwoFactorMapRenderer(Player player, String secret)
|
||||
{
|
||||
_player = player;
|
||||
|
||||
BitMatrix matrix;
|
||||
try
|
||||
{
|
||||
matrix = writer.encode(String.format("otpauth://totp/%s?secret=%s&issuer=Mineplex", _player.getName(), secret), BarcodeFormat.QR_CODE, 32, 32, ImmutableMap.of(EncodeHintType.MARGIN, 0));
|
||||
|
||||
}
|
||||
catch (WriterException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set background color to white
|
||||
for (byte[] column : contents)
|
||||
{
|
||||
Arrays.fill(column, (byte)32);
|
||||
}
|
||||
|
||||
String spacedSecret = Joiner.on(' ').join(Splitter.fixedLength(4).split(secret));
|
||||
renderText(contents, 2, 2, String.format(SETUP_TEXT, spacedSecret));
|
||||
renderQR(contents, 62, 62, matrix, 2);
|
||||
|
||||
}
|
||||
|
||||
private static void renderText(byte[][] contents, int startX, int startY, String text)
|
||||
{
|
||||
int x = startX;
|
||||
int y = startY;
|
||||
byte color = (byte)44;
|
||||
|
||||
for (int i = 0; i < text.length(); i++)
|
||||
{
|
||||
char c = text.charAt(i);
|
||||
if (c == '\n')
|
||||
{
|
||||
x = startX;
|
||||
y += FONT.getHeight() + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\u00A7')
|
||||
{
|
||||
int end = text.indexOf(';', i);
|
||||
if (end >= 0)
|
||||
{
|
||||
color = Byte.parseByte(text.substring(i+1, end));
|
||||
i = end;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
MapFont.CharacterSprite sprite = FONT.getChar(c);
|
||||
for (int k = 0; k < sprite.getWidth(); k++)
|
||||
{
|
||||
for (int l = 0; l < FONT.getHeight(); l++)
|
||||
{
|
||||
if (sprite.get(l, k))
|
||||
{
|
||||
if (x+k >= 128 || y+l >= 128)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
contents[x+k][y+l] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
x += sprite.getWidth() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderQR(byte[][] contents, int x, int y, BitMatrix matrix, int scale)
|
||||
{
|
||||
for (int matrixX = 0 ; matrixX < matrix.getWidth(); matrixX++)
|
||||
{
|
||||
for (int matrixY = 0; matrixY < matrix.getHeight(); matrixY++)
|
||||
{
|
||||
|
||||
if (matrix.get(matrixX, matrixY))
|
||||
{
|
||||
for (int i = 0; i < scale; i++)
|
||||
{
|
||||
for (int k = 0; k < scale; k++)
|
||||
{
|
||||
if (x + (matrixX * scale) + i >= 128 || y + (matrixY * scale) + k >= 128)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
contents[x + (matrixX * scale) + i][y + (matrixY * scale) + k] = QR_COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MapView mapView, MapCanvas mapCanvas, Player player)
|
||||
{
|
||||
if (player != _player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int x = 0; x < 128; x++)
|
||||
{
|
||||
for (int y = 0; y < 128; y++)
|
||||
{
|
||||
mapCanvas.setPixel(x, y, contents[x][y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package mineplex.core.twofactor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import mineplex.core.Managers;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
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 INSERT_LOGIN = "INSERT INTO twofactor_history (accountId,ip,loginTime) VALUES (?,?,NOW());";
|
||||
private final CoreClientManager _clientManager = Managers.require(CoreClientManager.class);
|
||||
private final DataSource _dataSource;
|
||||
|
||||
public TwoFactorRepository(DataSource source)
|
||||
{
|
||||
_dataSource = source;
|
||||
}
|
||||
|
||||
public ILoginProcessor buildSecretKeyLoginProcessor(BiConsumer<UUID, String> consumer)
|
||||
{
|
||||
return new ILoginProcessor()
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "Two-factor auth secret key grabber";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
consumer.accept(uuid, resultSet.getString(1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuery(int accountId, String uuid, String name)
|
||||
{
|
||||
return "SELECT secretKey FROM twofactor WHERE accountId=" + accountId + ";";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ILoginProcessor buildLastIpLoginProcessor(BiConsumer<UUID, String> consumer)
|
||||
{
|
||||
return new ILoginProcessor()
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "Two-factor auth last login grabber";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLoginResultSet(String playerName, UUID uuid, int accountId, ResultSet resultSet) throws SQLException
|
||||
{
|
||||
if (resultSet.next())
|
||||
{
|
||||
consumer.accept(uuid, resultSet.getString(1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuery(int accountId, String uuid, String name)
|
||||
{
|
||||
return "SELECT ip FROM twofactor_history WHERE accountId=" + accountId + " AND loginTime >= DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY loginTime DESC;";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> saveSecret(Player player, String secret)
|
||||
{
|
||||
int accountId = _clientManager.Get(player).getAccountId();
|
||||
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection connection = _dataSource.getConnection())
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement(INSERT_SECRET_KEY);
|
||||
statement.setInt(1, accountId);
|
||||
statement.setString(2, secret);
|
||||
statement.executeUpdate();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> saveLogin(Player player, String ip)
|
||||
{
|
||||
int accountId = _clientManager.Get(player).getAccountId();
|
||||
|
||||
return CompletableFuture.runAsync(() ->
|
||||
{
|
||||
try (Connection connection = _dataSource.getConnection())
|
||||
{
|
||||
PreparedStatement statement = connection.prepareStatement(INSERT_LOGIN);
|
||||
statement.setInt(1, accountId);
|
||||
statement.setString(2, ip);
|
||||
statement.executeUpdate();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,5 +1,15 @@
|
||||
package mineplex.game.clans;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.spigotmc.SpigotConfig;
|
||||
|
||||
import mineplex.core.CustomTagFix;
|
||||
import mineplex.core.FoodDupeFix;
|
||||
import mineplex.core.TimingsFix;
|
||||
@ -48,6 +58,7 @@ import mineplex.core.spawn.Spawn;
|
||||
import mineplex.core.stats.StatsManager;
|
||||
import mineplex.core.status.ServerStatusManager;
|
||||
import mineplex.core.teleport.Teleport;
|
||||
import mineplex.core.twofactor.TwoFactorAuth;
|
||||
import mineplex.core.updater.FileUpdater;
|
||||
import mineplex.core.updater.Updater;
|
||||
import mineplex.core.visibility.VisibilityManager;
|
||||
@ -60,14 +71,6 @@ import mineplex.game.clans.shop.mining.MiningShop;
|
||||
import mineplex.game.clans.shop.pvp.PvpShop;
|
||||
import mineplex.game.clans.spawn.travel.TravelShop;
|
||||
import mineplex.game.clans.world.WorldManager;
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.spigotmc.SpigotConfig;
|
||||
|
||||
import static mineplex.core.Managers.require;
|
||||
|
||||
@ -261,6 +264,8 @@ public class Clans extends JavaPlugin
|
||||
new MiningShop(_clansManager, _clientManager, _donationManager);
|
||||
new WorldManager(this);
|
||||
|
||||
require(TwoFactorAuth.class);
|
||||
|
||||
// Disable spigot item merging
|
||||
for (World world : getServer().getWorlds())
|
||||
{
|
||||
|
@ -1,5 +1,9 @@
|
||||
package mineplex.clanshub;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import mineplex.core.CustomTagFix;
|
||||
import mineplex.core.PacketsInteractionFix;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
@ -39,6 +43,7 @@ import mineplex.core.preferences.PreferencesManager;
|
||||
import mineplex.core.profileCache.ProfileCacheManager;
|
||||
import mineplex.core.punish.Punish;
|
||||
import mineplex.core.rankGiveaway.eternal.EternalGiveawayManager;
|
||||
import mineplex.core.rankGiveaway.titangiveaway.TitanGiveawayManager;
|
||||
import mineplex.core.recharge.Recharge;
|
||||
import mineplex.core.resourcepack.ResourcePackManager;
|
||||
import mineplex.core.serverConfig.ServerConfiguration;
|
||||
@ -47,9 +52,9 @@ import mineplex.core.status.ServerStatusManager;
|
||||
import mineplex.core.task.TaskManager;
|
||||
import mineplex.core.teleport.Teleport;
|
||||
import mineplex.core.thank.ThankManager;
|
||||
import mineplex.core.rankGiveaway.titangiveaway.TitanGiveawayManager;
|
||||
import mineplex.core.titles.Titles;
|
||||
import mineplex.core.titles.tracks.TrackManager;
|
||||
import mineplex.core.twofactor.TwoFactorAuth;
|
||||
import mineplex.core.updater.FileUpdater;
|
||||
import mineplex.core.updater.Updater;
|
||||
import mineplex.core.velocity.VelocityFix;
|
||||
@ -57,9 +62,6 @@ import mineplex.core.visibility.VisibilityManager;
|
||||
import mineplex.minecraft.game.core.combat.CombatManager;
|
||||
import mineplex.minecraft.game.core.condition.ConditionManager;
|
||||
import mineplex.minecraft.game.core.damage.DamageManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import static mineplex.core.Managers.require;
|
||||
|
||||
@ -175,6 +177,7 @@ public class ClansHub extends JavaPlugin
|
||||
|
||||
require(TrackManager.class);
|
||||
require(Titles.class);
|
||||
require(TwoFactorAuth.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,6 +52,7 @@ import mineplex.core.profileCache.ProfileCacheManager;
|
||||
import mineplex.core.projectile.ProjectileManager;
|
||||
import mineplex.core.punish.Punish;
|
||||
import mineplex.core.rankGiveaway.eternal.EternalGiveawayManager;
|
||||
import mineplex.core.rankGiveaway.titangiveaway.TitanGiveawayManager;
|
||||
import mineplex.core.recharge.Recharge;
|
||||
import mineplex.core.report.ReportManager;
|
||||
import mineplex.core.report.ReportPlugin;
|
||||
@ -63,7 +64,9 @@ import mineplex.core.status.ServerStatusManager;
|
||||
import mineplex.core.task.TaskManager;
|
||||
import mineplex.core.teleport.Teleport;
|
||||
import mineplex.core.thank.ThankManager;
|
||||
import mineplex.core.rankGiveaway.titangiveaway.TitanGiveawayManager;
|
||||
import mineplex.core.titles.Titles;
|
||||
import mineplex.core.titles.tracks.TrackManager;
|
||||
import mineplex.core.twofactor.TwoFactorAuth;
|
||||
import mineplex.core.updater.FileUpdater;
|
||||
import mineplex.core.updater.Updater;
|
||||
import mineplex.core.velocity.VelocityFix;
|
||||
@ -71,8 +74,6 @@ import mineplex.core.visibility.VisibilityManager;
|
||||
import mineplex.hub.modules.BillboardManager;
|
||||
import mineplex.hub.queue.QueueManager;
|
||||
import mineplex.hub.server.ServerManager;
|
||||
import mineplex.core.titles.Titles;
|
||||
import mineplex.core.titles.tracks.TrackManager;
|
||||
import mineplex.minecraft.game.classcombat.Class.ClassManager;
|
||||
import mineplex.minecraft.game.classcombat.Condition.SkillConditionManager;
|
||||
import mineplex.minecraft.game.classcombat.Skill.SkillFactory;
|
||||
@ -232,6 +233,7 @@ public class Hub extends JavaPlugin implements IRelation
|
||||
|
||||
require(TrackManager.class);
|
||||
require(Titles.class);
|
||||
require(TwoFactorAuth.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,7 +136,7 @@ import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||||
public class HubManager extends MiniClientPlugin<HubClient> implements IChatMessageFormatter
|
||||
{
|
||||
// ☃❅ Snowman!
|
||||
public HubType Type = HubType.Christmas;
|
||||
public HubType Type = HubType.Normal;
|
||||
|
||||
private BlockRestore _blockRestore;
|
||||
private CoreClientManager _clientManager;
|
||||
|
@ -1,36 +1,44 @@
|
||||
package nautilus.game.arcade;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.spigotmc.SpigotConfig;
|
||||
|
||||
import mineplex.core.CustomTagFix;
|
||||
import mineplex.core.FoodDupeFix;
|
||||
import mineplex.core.PacketsInteractionFix;
|
||||
import mineplex.core.TimingsFix;
|
||||
import mineplex.core.antihack.logging.AntihackLogger;
|
||||
import mineplex.core.chatsnap.SnapshotRepository;
|
||||
import mineplex.core.customdata.CustomDataManager;
|
||||
import mineplex.core.chatsnap.SnapshotManager;
|
||||
import mineplex.core.chatsnap.SnapshotPlugin;
|
||||
import mineplex.core.globalpacket.GlobalPacketManager;
|
||||
import net.minecraft.server.v1_8_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
import mineplex.core.account.CoreClientManager;
|
||||
import mineplex.core.achievement.AchievementManager;
|
||||
import mineplex.core.antihack.AntiHack;
|
||||
import mineplex.core.antihack.logging.AntihackLogger;
|
||||
import mineplex.core.blockrestore.BlockRestore;
|
||||
import mineplex.core.blood.Blood;
|
||||
import mineplex.core.boosters.BoosterManager;
|
||||
import mineplex.core.chat.Chat;
|
||||
import mineplex.core.chatsnap.SnapshotManager;
|
||||
import mineplex.core.chatsnap.SnapshotPlugin;
|
||||
import mineplex.core.chatsnap.SnapshotRepository;
|
||||
import mineplex.core.command.CommandCenter;
|
||||
import mineplex.core.common.events.ServerShutdownEvent;
|
||||
import mineplex.core.common.util.FileUtil;
|
||||
import mineplex.core.common.util.UtilServer;
|
||||
import mineplex.core.cosmetic.CosmeticManager;
|
||||
import mineplex.core.creature.Creature;
|
||||
import mineplex.core.customdata.CustomDataManager;
|
||||
import mineplex.core.disguise.DisguiseManager;
|
||||
import mineplex.core.donation.DonationManager;
|
||||
import mineplex.core.elo.EloManager;
|
||||
import mineplex.core.friend.FriendManager;
|
||||
import mineplex.core.gadget.GadgetManager;
|
||||
import mineplex.core.give.Give;
|
||||
import mineplex.core.globalpacket.GlobalPacketManager;
|
||||
import mineplex.core.hologram.HologramManager;
|
||||
import mineplex.core.ignore.IgnoreManager;
|
||||
import mineplex.core.incognito.IncognitoManager;
|
||||
@ -58,8 +66,7 @@ import mineplex.core.stats.StatsManager;
|
||||
import mineplex.core.status.ServerStatusManager;
|
||||
import mineplex.core.teleport.Teleport;
|
||||
import mineplex.core.thank.ThankManager;
|
||||
import mineplex.core.titles.Titles;
|
||||
import mineplex.core.titles.tracks.TrackManager;
|
||||
import mineplex.core.twofactor.TwoFactorAuth;
|
||||
import mineplex.core.updater.FileUpdater;
|
||||
import mineplex.core.updater.Updater;
|
||||
import mineplex.core.velocity.VelocityFix;
|
||||
@ -69,15 +76,6 @@ import mineplex.minecraft.game.core.damage.DamageManager;
|
||||
|
||||
import nautilus.game.arcade.anticheatmetadata.GameInfoMetadata;
|
||||
import nautilus.game.arcade.game.GameServerConfig;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.spigotmc.SpigotConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static mineplex.core.Managers.require;
|
||||
|
||||
public class Arcade extends JavaPlugin
|
||||
@ -198,6 +196,8 @@ public class Arcade extends JavaPlugin
|
||||
new CustomTagFix(this, packetHandler);
|
||||
new PacketsInteractionFix(this, packetHandler);
|
||||
new FoodDupeFix(this);
|
||||
|
||||
require(TwoFactorAuth.class);
|
||||
|
||||
//Updates
|
||||
getServer().getScheduler().scheduleSyncRepeatingTask(this, new Updater(this), 1, 1);
|
||||
|
@ -351,8 +351,8 @@ public class ArcadeManager extends MiniPlugin implements IRelation
|
||||
TitanGiveawayManager titanGiveaway = new TitanGiveawayManager(getPlugin(), clientManager, serverStatusManager);
|
||||
EternalGiveawayManager eternalGiveawayManager = new EternalGiveawayManager(getPlugin(), clientManager, serverStatusManager);
|
||||
|
||||
new HolidayManager(this, titanGiveaway, eternalGiveawayManager);
|
||||
IsHolidayEnabled = true;
|
||||
//new HolidayManager(this, titanGiveaway, eternalGiveawayManager);
|
||||
IsHolidayEnabled = false;
|
||||
|
||||
new ValentinesGiftManager(plugin, clientManager, _bonusManager.getRewardManager(), inventoryManager, _cosmeticManager.getGadgetManager(), statsManager);
|
||||
new GameTestingManager(this);
|
||||
|
@ -292,7 +292,7 @@ public abstract class Game implements Listener
|
||||
public long PrepareTime = 9000;
|
||||
public boolean PlaySoundGameStart = true;
|
||||
|
||||
public double XpMult = 2;
|
||||
public double XpMult = 1;
|
||||
|
||||
public boolean SpeedMeasurement = false;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class GameRewardManager implements Listener
|
||||
{
|
||||
ArcadeManager Manager;
|
||||
|
||||
boolean DoubleGem = true;
|
||||
boolean DoubleGem = false;
|
||||
boolean TimeReward = true;
|
||||
|
||||
public GameRewardManager(ArcadeManager manager)
|
||||
@ -352,7 +352,7 @@ public class GameRewardManager implements Listener
|
||||
//Double Gem
|
||||
if (DoubleGem && game.GemDoubleEnabled)
|
||||
{
|
||||
UtilPlayer.message(player, F.elem(C.cGreen + "+" + (earnedGems) + " Gems") + " for " + F.elem(C.cDGreen + "Holiday Double Gems"));
|
||||
UtilPlayer.message(player, F.elem(C.cGreen + "+" + (earnedGems) + " Gems") + " for " + F.elem(C.cDGreen + "Double Gem Weekend"));
|
||||
|
||||
totalGems += earnedGems;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user