Skip to content

Commit

Permalink
Add support for sensitive data in dumps (GeyserMC#1149)
Browse files Browse the repository at this point in the history
* Add sensitive dumps

* Add better arg handling and offline dumps

* Add sensitive parameters for plugin IPs

* Add sensitive property to the Bedrock remote address

Co-authored-by: Camotoy <[email protected]>
  • Loading branch information
rtm516 and Camotoy authored Aug 15, 2020
1 parent 4bcf446 commit 4af17df
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lombok.Getter;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;

import java.util.ArrayList;
Expand All @@ -52,7 +53,13 @@ public class GeyserBungeeDumpInfo extends BootstrapDumpInfo {
this.plugins = new ArrayList<>();

for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) {
this.listeners.add(new ListenerInfo(listener.getHost().getHostString(), listener.getHost().getPort()));
String hostname;
if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) {
hostname = listener.getHost().getHostString();
} else {
hostname = "***";
}
this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort()));
}

for (Plugin plugin : proxy.getPluginManager().getPlugins()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;

import java.util.ArrayList;
Expand All @@ -50,7 +51,11 @@ public class GeyserSpigotDumpInfo extends BootstrapDumpInfo {
this.platformVersion = Bukkit.getVersion();
this.platformAPIVersion = Bukkit.getBukkitVersion();
this.onlineMode = Bukkit.getOnlineMode();
this.serverIP = Bukkit.getIp();
if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) {
this.serverIP = Bukkit.getIp();
} else {
this.serverIP = "***";
}
this.serverPort = Bukkit.getPort();
this.plugins = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.BootstrapDumpInfo;

import java.util.ArrayList;
Expand All @@ -50,7 +51,11 @@ public class GeyserVelocityDumpInfo extends BootstrapDumpInfo {
this.platformVersion = proxy.getVersion().getVersion();
this.platformVendor = proxy.getVersion().getVendor();
this.onlineMode = proxy.getConfiguration().isOnlineMode();
this.serverIP = proxy.getBoundAddress().getHostString();
if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) {
this.serverIP = proxy.getBoundAddress().getHostString();
} else {
this.serverIP = "***";
}
this.serverPort = proxy.getBoundAddress().getPort();
this.plugins = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.DumpInfo;
import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.WebUtils;

import java.io.FileOutputStream;
import java.io.IOException;

public class DumpCommand extends GeyserCommand {
Expand All @@ -49,43 +51,80 @@ public DumpCommand(GeyserConnector connector, String name, String description, S
super(name, description, permission);

this.connector = connector;

final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("dump_user_auth", SimpleBeanPropertyFilter.serializeAllExcept(new String[] {"password"}));

MAPPER.setFilterProvider(filter);
}

@Override
public void execute(CommandSender sender, String[] args) {
boolean showSensitive = false;
boolean offlineDump = false;
if (args.length >= 1) {
for (String arg : args) {
switch (arg) {
case "full":
showSensitive = true;
break;
case "offline":
offlineDump = true;
break;

}
}
}

AsteriskSerializer.showSensitive = showSensitive;

sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collecting"));
String dumpData = "";
try {
dumpData = MAPPER.writeValueAsString(new DumpInfo());
if (offlineDump) {
dumpData = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(new DumpInfo());
} else {
dumpData = MAPPER.writeValueAsString(new DumpInfo());
}
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
return;
}

sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading"));
String response;
JsonNode responseNode;
try {
response = WebUtils.post(DUMP_URL + "documents", dumpData);
responseNode = MAPPER.readTree(response);
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
return;
}
String uploadedDumpUrl = "";

if (!responseNode.has("key")) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
return;
if (offlineDump) {
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.writing"));

try {
FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile());
outputStream.write(dumpData.getBytes());
outputStream.close();
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e);
return;
}

uploadedDumpUrl = "dump.json";
} else {
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading"));

String response;
JsonNode responseNode;
try {
response = WebUtils.post(DUMP_URL + "documents", dumpData);
responseNode = MAPPER.readTree(response);
} catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error"));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
return;
}

if (!responseNode.has("key")) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
return;
}

uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
}

String uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.message") + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
if (!sender.isConsole()) {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,46 @@
import java.util.Optional;

public class AsteriskSerializer extends StdSerializer<Object> implements ContextualSerializer {

public static boolean showSensitive = false;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = AsteriskSerializer.class)
public @interface Asterisk {
String value() default "***";
boolean sensitive() default false;
}

String asterisk;
boolean sensitive;

public AsteriskSerializer() {
super(Object.class);
}

public AsteriskSerializer(String asterisk) {
public AsteriskSerializer(String asterisk, boolean sensitive) {
super(Object.class);
this.asterisk = asterisk;
this.sensitive = sensitive;
}

@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty property) {
Optional<Asterisk> anno = Optional.ofNullable(property)
.map(prop -> prop.getAnnotation(Asterisk.class));
return new AsteriskSerializer(anno.map(Asterisk::value).orElse(null));

return new AsteriskSerializer(anno.map(Asterisk::value).orElse(null), anno.map(Asterisk::sensitive).orElse(null));
}

@Override
public void serialize(Object obj, JsonGenerator gen, SerializerProvider prov) throws IOException {
if (sensitive && showSensitive) {
gen.writeObject(obj);
return;
}

gen.writeString(asterisk);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
@Getter
public static class BedrockConfiguration implements IBedrockConfiguration {

@AsteriskSerializer.Asterisk(sensitive = true)
private String address;

@Setter
Expand All @@ -114,6 +115,7 @@ public static class BedrockConfiguration implements IBedrockConfiguration {
public static class RemoteConfiguration implements IRemoteConfiguration {

@Setter
@AsteriskSerializer.Asterisk(sensitive = true)
private String address;

@Setter
Expand Down
2 changes: 1 addition & 1 deletion connector/src/main/resources/languages

0 comments on commit 4af17df

Please sign in to comment.