1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2025-03-11 02:19:56 +07:00

Many fixes to admin/trace/UUID system

This commit is contained in:
Anuken 2018-06-13 17:52:31 -04:00
parent c077f6e1e8
commit d0302cdbf3
14 changed files with 155 additions and 91 deletions
android/src/io/anuke/mindustry
core/src/io/anuke/mindustry
desktop/src/io/anuke/mindustry/desktop
html/src/io/anuke/mindustry/client
kryonet/src/io/anuke/kryonet
server/src/io/anuke/mindustry/server

View File

@ -28,7 +28,6 @@ import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.io.Saves.SaveSlot;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.scene.ui.layout.Unit;
@ -45,7 +44,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
import static io.anuke.mindustry.Vars.*;
@ -106,7 +104,7 @@ public class AndroidLauncher extends AndroidApplication{
}
@Override
public byte[] getUUID() {
public String getUUID() {
try {
String s = Secure.getString(getContext().getContentResolver(),
Secure.ANDROID_ID);
@ -118,21 +116,13 @@ public class AndroidLauncher extends AndroidApplication{
+ Character.digit(s.charAt(i + 1), 16));
}
if(new String(Base64Coder.encode(data)).equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID.");
String result = new String(Base64Coder.encode(data));
return data;
if(result.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID.");
return result;
}catch (Exception e){
String uuid = Settings.getString("uuid", "");
if(uuid.isEmpty()){
byte[] result = new byte[8];
new Random().nextBytes(result);
uuid = new String(Base64Coder.encode(result));
Settings.putString("uuid", uuid);
Settings.save();
return result;
}
return Base64Coder.decode(uuid);
return super.getUUID();
}
}

View File

@ -1,6 +1,7 @@
package io.anuke.mindustry.core;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.Pools;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.annotations.Annotations.Variant;
@ -14,6 +15,8 @@ import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Net.SendMode;
import io.anuke.mindustry.net.NetworkIO;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.net.TraceInfo;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
@ -25,6 +28,7 @@ import io.anuke.ucore.util.Timer;
import java.io.DataInputStream;
import java.util.Arrays;
import java.util.Random;
import static io.anuke.mindustry.Vars.*;
@ -73,6 +77,7 @@ public class NetClient extends Module {
c.name = player.name;
c.mobile = mobile;
c.color = Color.rgba8888(player.color);
c.usid = getUsid(packet.addressTCP);
c.uuid = Platform.instance.getUUID();
if(c.uuid == null){
@ -170,6 +175,18 @@ public class NetClient extends Module {
}
}
String getUsid(String ip){
if(Settings.getString("usid-" + ip, null) != null){
return Settings.getString("usid-" + ip);
}else{
byte[] bytes = new byte[8];
new Random().nextBytes(bytes);
String result = new String(Base64Coder.encode(bytes));
Settings.putString("usid-" + ip, result);
return result;
}
}
@Remote(variants = Variant.one)
public static void onKick(KickReason reason){
netClient.disconnectQuietly();
@ -184,6 +201,12 @@ public class NetClient extends Module {
players[0].y = y;
}
@Remote(variants = Variant.one)
public static void onTraceInfo(TraceInfo info){
Player player = playerGroup.getByID(info.playerid);
ui.traces.show(player, info);
}
@Remote(variants = Variant.one, unreliable = true)
public static void onSnapshot(byte[] snapshot, int snapshotID){
//skip snapshot IDs that have already been recieved

View File

@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Colors;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.annotations.Annotations.Loc;
@ -75,7 +74,7 @@ public class NetServer extends Module{
});
Net.handleServer(ConnectPacket.class, (id, packet) -> {
String uuid = new String(Base64Coder.encode(packet.uuid));
String uuid = packet.uuid;
if(Net.getConnection(id) == null ||
admins.isIPBanned(Net.getConnection(id).address)) return;
@ -127,8 +126,9 @@ public class NetServer extends Module{
}
Player player = new Player();
player.isAdmin = admins.isAdmin(uuid, ip);
player.isAdmin = admins.isAdmin(uuid, packet.usid);
player.clientid = id;
player.usid = packet.usid;
player.name = packet.name;
player.uuid = uuid;
player.mech = packet.mobile ? Mechs.standardShip : Mechs.standard;
@ -387,6 +387,39 @@ public class NetServer extends Module{
}
}
@Remote(targets = Loc.client, called = Loc.server)
public static void onAdminRequest(Player player, Player other, AdminAction action){
if(!player.isAdmin){
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
player.name, Net.getConnection(player.clientid).address);
return;
}
if(other == null || other.isAdmin){
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
return;
}
String ip = Net.getConnection(other.clientid).address;
if(action == AdminAction.ban){
netServer.admins.banPlayerIP(ip);
netServer.kick(other.clientid, KickReason.banned);
Log.info("&lc{0} has banned {1}.", player.name, other.name);
}else if(action == AdminAction.kick){
netServer.kick(other.clientid, KickReason.kick);
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
}else if(action == AdminAction.trace){
if(player.clientid != -1) {
Call.onTraceInfo(player.clientid, netServer.admins.getTraceByID(other.uuid));
}else{
NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid));
}
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
}
}
@Remote(targets = Loc.client)
public static void connectConfirm(Player player){
player.add();

View File

@ -47,8 +47,8 @@ public abstract class Platform {
}
/**Whether debug mode is enabled.*/
public boolean isDebug(){return false;}
/**Must be 8 bytes in length.*/
public byte[] getUUID(){
/**Must be a base64 string 8 bytes in length.*/
public String getUUID(){
String uuid = Settings.getString("uuid", "");
if(uuid.isEmpty()){
byte[] result = new byte[8];
@ -56,9 +56,9 @@ public abstract class Platform {
uuid = new String(Base64Coder.encode(result));
Settings.putString("uuid", uuid);
Settings.save();
return result;
return uuid;
}
return Base64Coder.decode(uuid);
return uuid;
}
/**Only used for iOS or android: open the share menu for a map or save.*/
public void shareFile(FileHandle file){}

View File

@ -53,7 +53,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
public float pointerX, pointerY;
public String name = "name";
public String uuid;
public String uuid, usid;
public boolean isAdmin, isTransferring, isShooting;
public Color color = new Color();
@ -651,6 +651,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
public void write(DataOutput buffer) throws IOException {
super.writeSave(buffer, !isLocal);
buffer.writeUTF(name);
buffer.writeBoolean(isAdmin);
buffer.writeInt(Color.rgba8888(color));
buffer.writeBoolean(dead);
buffer.writeByte(weapon.id);
@ -662,6 +663,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
float lastx = x, lasty = y, lastrot = rotation;
super.readSave(buffer);
name = buffer.readUTF();
isAdmin = buffer.readBoolean();
color.set(buffer.readInt());
dead = buffer.readBoolean();
weapon = Upgrade.getByID(buffer.readByte());

View File

@ -1,6 +1,7 @@
package io.anuke.mindustry.io;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Base64Coder;
import io.anuke.annotations.Annotations.ReadClass;
import io.anuke.annotations.Annotations.WriteClass;
import io.anuke.mindustry.entities.Player;
@ -10,8 +11,11 @@ import io.anuke.mindustry.entities.traits.CarriableTrait;
import io.anuke.mindustry.entities.traits.CarryTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.mindustry.net.Packets.KickReason;
import io.anuke.mindustry.net.TraceInfo;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
@ -129,6 +133,16 @@ public class TypeIO {
return Team.values()[buffer.get()];
}
@WriteClass(AdminAction.class)
public static void writeAction(ByteBuffer buffer, AdminAction reason){
buffer.put((byte)reason.ordinal());
}
@ReadClass(AdminAction.class)
public static AdminAction readAction(ByteBuffer buffer){
return AdminAction.values()[buffer.get()];
}
@WriteClass(Effect.class)
public static void writeEffect(ByteBuffer buffer, Effect effect){
buffer.putShort((short)effect.id);
@ -245,4 +259,45 @@ public class TypeIO {
buffer.get(bytes);
return bytes;
}
@WriteClass(TraceInfo.class)
public static void writeTrace(ByteBuffer buffer, TraceInfo info){
buffer.putInt(info.playerid);
buffer.putShort((short)info.ip.getBytes().length);
buffer.put(info.ip.getBytes());
buffer.put(info.modclient ? (byte)1 : 0);
buffer.put(info.android ? (byte)1 : 0);
buffer.putInt(info.totalBlocksBroken);
buffer.putInt(info.structureBlocksBroken);
buffer.putInt(info.lastBlockBroken.id);
buffer.putInt(info.totalBlocksPlaced);
buffer.putInt(info.lastBlockPlaced.id);
buffer.put(Base64Coder.decode(info.uuid));
}
@ReadClass(TraceInfo.class)
public static TraceInfo readTrace(ByteBuffer buffer){
int id = buffer.getInt();
short iplen = buffer.getShort();
byte[] ipb = new byte[iplen];
buffer.get(ipb);
TraceInfo info = new TraceInfo(new String(ipb));
info.playerid = id;
info.modclient = buffer.get() == 1;
info.android = buffer.get() == 1;
info.totalBlocksBroken = buffer.getInt();
info.structureBlocksBroken = buffer.getInt();
info.lastBlockBroken = Block.getByID(buffer.getInt());
info.totalBlocksPlaced = buffer.getInt();
info.lastBlockPlaced = Block.getByID(buffer.getInt());
byte[] uuid = new byte[8];
buffer.get(uuid);
info.uuid = new String(Base64Coder.encode(uuid));
return info;
}
}

View File

@ -270,13 +270,13 @@ public class Administration {
}
/**Makes a player an admin. Returns whether this player was already an admin.*/
public boolean adminPlayer(String id, String ip){
public boolean adminPlayer(String id, String usid){
PlayerInfo info = getCreateInfo(id);
if(info.admin)
return false;
info.validAdminIP = ip;
info.adminUsid = usid;
info.admin = true;
save();
@ -304,9 +304,9 @@ public class Administration {
return getCreateInfo(uuid).banned;
}
public boolean isAdmin(String id, String ip){
public boolean isAdmin(String id, String usip){
PlayerInfo info = getCreateInfo(id);
return info.admin && ip.equals(info.validAdminIP);
return info.admin && usip.equals(info.adminUsid);
}
public Array<PlayerInfo> findByName(String name, boolean last){
@ -375,9 +375,9 @@ public class Administration {
public static class PlayerInfo{
public String id;
public String lastName = "<unknown>", lastIP = "<unknown>";
public String validAdminIP;
public Array<String> ips = new Array<>();
public Array<String> names = new Array<>();
public String adminUsid;
public int timesKicked;
public int timesJoined;
public int totalBlockPlaced;

View File

@ -1,5 +1,6 @@
package io.anuke.mindustry.net;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.Player;
@ -30,29 +31,30 @@ public class Packets {
public static class ConnectPacket implements Packet{
public int version;
public int players;
public String name;
public String name, uuid, usid;
public boolean mobile;
public int color;
public byte[] uuid;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(Version.build);
IOUtils.writeString(buffer, name);
IOUtils.writeString(buffer, usid);
buffer.put(mobile ? (byte)1 : 0);
buffer.putInt(color);
buffer.put(uuid);
buffer.put(Base64Coder.decode(uuid));
}
@Override
public void read(ByteBuffer buffer) {
version = buffer.getInt();
name = IOUtils.readString(buffer);
usid = IOUtils.readString(buffer);
mobile = buffer.get() == 1;
color = buffer.getInt();
uuid = new byte[8];
buffer.get(uuid);
byte[] idbytes = new byte[8];
buffer.get(idbytes);
uuid = new String(Base64Coder.encode(idbytes));
}
}

View File

@ -4,10 +4,11 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.net.EditLog;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.net.Packets.KickReason;
import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.mindustry.ui.BorderImage;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.ucore.core.Inputs;
@ -138,23 +139,10 @@ public class PlayerListFragment implements Fragment{
//TODO requests.
t.addImageButton("icon-ban", 14*2, () -> {
ui.showConfirm("$text.confirm", "$text.confirmban", () -> {
if(Net.server()) {
netServer.admins.banPlayerIP(connection.address);
netServer.kick(player.clientid, KickReason.banned);
}else{
//NetEvents.handleAdministerRequest(player, AdminAction.ban);
}
});
ui.showConfirm("$text.confirm", "$text.confirmban", () -> Call.onAdminRequest(player, AdminAction.ban));
}).padBottom(-5.1f);
t.addImageButton("icon-cancel", 14*2, () -> {
if(Net.server()) {
netServer.kick(player.clientid, KickReason.kick);
}else{
//NetEvents.handleAdministerRequest(player, AdminAction.kick);
}
}).padBottom(-5.1f);
t.addImageButton("icon-cancel", 14*2, () -> Call.onAdminRequest(player, AdminAction.kick)).padBottom(-5.1f);
t.row();
@ -166,12 +154,10 @@ public class PlayerListFragment implements Fragment{
if(netServer.admins.isAdmin(id, connection.address)){
ui.showConfirm("$text.confirm", "$text.confirmunadmin", () -> {
netServer.admins.unAdminPlayer(id);
//CallClient.adminSet(player, false);
});
}else{
ui.showConfirm("$text.confirm", "$text.confirmadmin", () -> {
netServer.admins.adminPlayer(id, connection.address);
//CallClient.adminSet(player, true);
netServer.admins.adminPlayer(id, player.usid);
});
}
}).update(b ->{
@ -179,7 +165,7 @@ public class PlayerListFragment implements Fragment{
b.setDisabled(Net.client());
}).get().setTouchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled);
t.addImageButton("icon-zoom-small", 14*2, () -> {}/*NetEvents.handleTraceRequest(player)*/);
t.addImageButton("icon-zoom-small", 14*2, () -> Call.onAdminRequest(player, AdminAction.trace));
}).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs);

View File

@ -11,7 +11,6 @@ import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.util.OS;
import io.anuke.ucore.util.Strings;
@ -23,7 +22,6 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Random;
import static io.anuke.mindustry.Vars.*;
@ -113,7 +111,7 @@ public class DesktopPlatform extends Platform {
}
@Override
public byte[] getUUID() {
public String getUUID() {
try {
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
NetworkInterface out;
@ -123,22 +121,13 @@ public class DesktopPlatform extends Platform {
byte[] result = new byte[8];
System.arraycopy(bytes, 0, result, 0, bytes.length);
if(new String(Base64Coder.encode(result)).equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID.");
String str = new String(Base64Coder.encode(result));
return result;
if(str.equals("AAAAAAAAAOA=")) throw new RuntimeException("Bad UUID.");
return str;
}catch (Exception e){
Settings.defaults("uuid", "");
String uuid = Settings.getString("uuid");
if(uuid.isEmpty()){
byte[] result = new byte[8];
new Random().nextBytes(result);
uuid = new String(Base64Coder.encode(result));
Settings.putString("uuid", uuid);
Settings.save();
return result;
}
return Base64Coder.decode(uuid);
return super.getUUID();
}
}

View File

@ -19,13 +19,11 @@ import com.google.gwt.user.client.ui.*;
import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.function.Consumer;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.Random;
public class HtmlLauncher extends GwtApplication {
static final int WIDTH = 800;
@ -126,22 +124,6 @@ public class HtmlLauncher extends GwtApplication {
return !ref.startsWith("https") && !ref.contains("itch.io");
}
@Override
public byte[] getUUID(){
Settings.defaults("uuid", "");
String uuid = Settings.getString("uuid");
if(uuid.isEmpty()){
byte[] result = new byte[8];
new Random().nextBytes(result);
uuid = new String(Base64Coder.encode(result));
Settings.putString("uuid", uuid);
Settings.save();
return result;
}
return Base64Coder.decode(uuid);
}
@Override
public void downloadFile(String name, byte[] bytes) {
downloadBytes(name, new String(Base64Coder.encode(bytes)));

View File

@ -57,6 +57,7 @@ public class WebsocketClient implements ClientProvider {
@Override
public void onOpen() {
Connect connect = new Connect();
connect.addressTCP = ip;
Net.handleClientReceived(connect);
}
});

View File

@ -60,6 +60,7 @@ public class KryoClient implements ClientProvider{
@Override
public void connected (Connection connection) {
Connect c = new Connect();
c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress();
c.id = connection.getID();
if(connection.getRemoteAddressTCP() != null) c.addressTCP = connection.getRemoteAddressTCP().toString();

View File

@ -439,7 +439,7 @@ public class ServerControl extends Module {
}
if(target != null){
netServer.admins.adminPlayer(target.uuid, Net.getConnection(target.clientid).address);
netServer.admins.adminPlayer(target.uuid, target.usid);
info("Admin-ed player by ID: {0} / {1}", target.uuid, arg[0]);
}else{
info("Nobody with that name could be found.");