GDPR query processor #271
29
src/GDPRQueryREADME.md
Normale Datei
29
src/GDPRQueryREADME.md
Normale Datei
@ -0,0 +1,29 @@
|
||||
# SteamWar GDPR report
|
||||
|
||||
## Copyright notice
|
||||
The provided build worlds contain the world design of SteamWar contributors and is subject to their copyright.
|
||||
The build worlds are therefore provided for personal use only.
|
||||
|
||||
## Categories of personal data processed
|
||||
- IP address
|
||||
- Minecraft account
|
||||
- E-Mail address (if using a website account)
|
||||
|
||||
## Processing purposes of personal data and person-related data
|
||||
- Provision of SteamWar user functionality (Minecraft account, IP address, BuildWorlds, BuildInventories, BuildMembers, Elo, IgnoredPlayers, SchematicMembers, SchematicChecksessions, Schematics, PersonalKits, UserData, UserConfigs)
|
||||
- Manual analysis and punishment of player misbehaviour (BannedIPs, log files, Punishments)
|
||||
- Statistical analysis (Sessions, Fights, SchematicChecksessions)
|
||||
- Historical data storage (Fights)
|
||||
- Technical error analysis (log files)
|
||||
- Provision of the SteamWar website functionality (IP address, E-Mail address)
|
||||
|
||||
## Data Accessors
|
||||
- SteamWar software
|
||||
- SteamWar Administration
|
||||
- SteamWar Development
|
||||
- SteamWar Moderation (limited to Punishments and SchematicChecksessions)
|
||||
|
||||
## Storage duration
|
||||
- Data for provision of functionality is stored until user triggered deletion
|
||||
- Log file storage duration is targeted at one month, but might differ due to technical reasons
|
||||
- Historical and statistical data deletion is not intended
|
@ -1,7 +1,10 @@
|
||||
package de.steamwar.bungeecore.commands;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.sql.Statement;
|
||||
import de.steamwar.bungeecore.sql.SteamwarUser;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
@ -12,35 +15,47 @@ import java.util.zip.ZipOutputStream;
|
||||
public class GDPRQuery extends BasicCommand {
|
||||
|
||||
public GDPRQuery() {
|
||||
super("gdprquery", null);
|
||||
super("gdprquery", "bungeecore.softreload");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
|
||||
try {
|
||||
createZip(user);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not create zip", e);
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
SteamwarUser user = args.length == 0 ? SteamwarUser.get(player.getUniqueId()) : SteamwarUser.get(args[0]);
|
||||
if(user == null) {
|
||||
Message.send("UNKNOWN_PLAYER", player);
|
||||
return;
|
||||
}
|
||||
|
||||
BungeeCord.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> {
|
||||
try {
|
||||
createZip(player, user);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not create zip", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createZip(SteamwarUser user) throws IOException {
|
||||
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("test.zip")); //TODO
|
||||
private void createZip(ProxiedPlayer player, SteamwarUser user) throws IOException {
|
||||
printUpdate(player, "GDPR_STATUS_WEBSITE");
|
||||
|
||||
//TODO: Bauweltenurheberrecht
|
||||
//TODO: Erklärung Art, Umfang (& Dauer?)
|
||||
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(user.getUserName() + ".zip"));
|
||||
|
||||
copy(getClass().getClassLoader().getResourceAsStream("GDPRQueryREADME.md"), out, "README.md");
|
||||
copy(getClass().getClassLoader().getResourceAsStream("GDPRQueryREADME.md"), out, "README.txt");
|
||||
|
||||
printUpdate(player, "GDPR_STATUS_WORLD");
|
||||
copyBauwelt(user, out, "/home/minecraft/userworlds/" + user.getUuid().toString(), "BuildWorld12");
|
||||
copyBauwelt(user, out, "/home/minecraft/userworlds15/" + user.getId(), "BuildWorld15");
|
||||
|
||||
printUpdate(player, "GDPR_STATUS_INVENTORIES");
|
||||
copyPlayerdata(user, out, "/home/minecraft/userworlds", "BuildInventories12");
|
||||
copyPlayerdata(user, out, "/home/minecraft/userworlds15", "BuildInventories15");
|
||||
//TODO: Simulatoren von allen Bauwelten
|
||||
|
||||
printUpdate(player, "GDPR_STATUS_DATABASE");
|
||||
sqlCSV(user, out, bannedIPs, "BannedIPs.csv");
|
||||
sqlCSV(user, out, bauweltMember, "BuildMember.csv");
|
||||
sqlCSV(user, out, bauweltMembers, "BuildMembers.csv");
|
||||
@ -62,10 +77,11 @@ public class GDPRQuery extends BasicCommand {
|
||||
schematics(user, out);
|
||||
userConfig(user, out);
|
||||
|
||||
//TODO: Logs: Lobby & Bungeelogpos!
|
||||
//TODO: Website
|
||||
printUpdate(player, "GDPR_STATUS_LOGS");
|
||||
copyLogs(user, out, new File("/logs"), "logs");
|
||||
|
||||
out.close();
|
||||
printUpdate(player, "GDPR_STATUS_FINISHED");
|
||||
}
|
||||
|
||||
private static final Statement bannedIPs = new Statement("SELECT Timestamp, IP FROM BannedUserIPs WHERE UserID = ?");
|
||||
@ -89,36 +105,34 @@ public class GDPRQuery extends BasicCommand {
|
||||
private static final Statement userConfig = new Statement("SELECT * FROM UserConfig WHERE User = ?");
|
||||
|
||||
private void sqlCSV(SteamwarUser user, ZipOutputStream out, Statement statement, String path) throws IOException {
|
||||
write(stream -> {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream);
|
||||
statement.select(rs -> {
|
||||
try {
|
||||
int columns = rs.getMetaData().getColumnCount();
|
||||
write(stream -> statement.select(rs -> {
|
||||
try {
|
||||
OutputStreamWriter writer = new OutputStreamWriter(stream);
|
||||
int columns = rs.getMetaData().getColumnCount();
|
||||
|
||||
for(int i = 1; i <= columns; i++) {
|
||||
writer.write(rs.getMetaData().getColumnLabel(i));
|
||||
writer.write(";");
|
||||
}
|
||||
writer.write("\n");
|
||||
|
||||
while(rs.next()) {
|
||||
for(int i = 1; i <= columns; i++) {
|
||||
writer.write(rs.getMetaData().getColumnLabel(i));
|
||||
try {
|
||||
writer.write(rs.getString(i));
|
||||
} catch (NullPointerException e) {
|
||||
// ignored
|
||||
}
|
||||
writer.write(";");
|
||||
}
|
||||
writer.write("\n");
|
||||
|
||||
while(rs.next()) {
|
||||
for(int i = 1; i <= columns; i++) {
|
||||
try {
|
||||
writer.write(rs.getString(i));
|
||||
} catch (NullPointerException e) {
|
||||
// ignored
|
||||
}
|
||||
writer.write(";");
|
||||
}
|
||||
writer.write("\n");
|
||||
}
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not write file", e);
|
||||
}
|
||||
return null;
|
||||
}, user.getId());
|
||||
}, out, path);
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not write file", e);
|
||||
}
|
||||
return null;
|
||||
}, user.getId()), out, path);
|
||||
}
|
||||
|
||||
private void personalKits(SteamwarUser user, ZipOutputStream out) {
|
||||
@ -169,8 +183,18 @@ public class GDPRQuery extends BasicCommand {
|
||||
}, user.getId());
|
||||
}
|
||||
|
||||
private void copyLogs(SteamwarUser user, ZipOutputStream out, File log, String outFile) throws IOException {
|
||||
if (log.isDirectory()) {
|
||||
for(File logfile : log.listFiles()) {
|
||||
copyLogs(user, out, logfile, outFile + "/" + logfile.getName().replace(".gz", ""));
|
||||
}
|
||||
} else {
|
||||
Process reader = new ProcessBuilder("zgrep", "^.*" + user.getUserName() + "\\( issued server command:\\| moved too quickly!\\| executed command:\\| lost connection:\\||\\|»\\|\\[\\|\\]\\).*$", log.getPath()).start();
|
||||
copy(reader.getInputStream(), out, outFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyBauwelt(SteamwarUser user, ZipOutputStream out, String inDir, String outDir) throws IOException {
|
||||
//TODO: Überhaupt nötig wegen Urheberrecht?
|
||||
File world = new File(inDir);
|
||||
if(!world.exists())
|
||||
return;
|
||||
@ -208,22 +232,37 @@ public class GDPRQuery extends BasicCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(File file, ZipOutputStream out, String path) throws IOException {
|
||||
private void printUpdate(ProxiedPlayer player, String message) {
|
||||
if (player.isConnected())
|
||||
Message.send(message, player);
|
||||
}
|
||||
|
||||
private void copy(File file, ZipOutputStream out, String path) throws IOException {
|
||||
try(FileInputStream in = new FileInputStream(file)) {
|
||||
copy(in, out, path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(InputStream in, ZipOutputStream out, String path) throws IOException {
|
||||
write(stream -> {
|
||||
int bytes;
|
||||
for(byte[] buf = new byte[8192]; (bytes = in.read(buf)) > 0; ) {
|
||||
out.write(buf, 0, bytes);
|
||||
private void copy(InputStream in, ZipOutputStream out, String path) throws IOException {
|
||||
boolean initialized = false;
|
||||
|
||||
int bytes;
|
||||
for(byte[] buf = new byte[8192]; (bytes = in.read(buf)) > 0; ) {
|
||||
if(!initialized) {
|
||||
ZipEntry entry = new ZipEntry(path);
|
||||
out.putNextEntry(entry);
|
||||
initialized = true;
|
||||
}
|
||||
}, out, path);
|
||||
|
||||
out.write(buf, 0, bytes);
|
||||
}
|
||||
|
||||
if(initialized) {
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static void write(Writer writer, ZipOutputStream out, String path) throws IOException {
|
||||
private void write(Writer writer, ZipOutputStream out, String path) throws IOException {
|
||||
ZipEntry entry = new ZipEntry(path);
|
||||
out.putNextEntry(entry);
|
||||
writer.accept(out);
|
||||
|
@ -549,4 +549,12 @@ VERIFY_SUCCESS=§7Erfolgreich mit dem Discord Account §e{0} §7verknüpft
|
||||
#Discord
|
||||
DISCORD_TICKET_MESSAGE=§7Ticket §e{0}§7» §f§l{1}: §7{2}
|
||||
DISCORD_TICKET_NEW=§7Ticket §e{0}§7» §aTicket wurde geöffnet!
|
||||
DISCORD_TICKET_CLOSED=§7Ticket §e{0}§7» §cTicket wurde geschlossen!
|
||||
DISCORD_TICKET_CLOSED=§7Ticket §e{0}§7» §cTicket wurde geschlossen!
|
||||
|
||||
#GDPR Query
|
||||
GDPR_STATUS_WEBSITE=§7Website kann nicht automatisiert gepackt werden und muss daher manuell hinzugefügt werden.
|
||||
GDPR_STATUS_WORLD=§7Packe Bauwelten...
|
||||
GDPR_STATUS_INVENTORIES=§7Suche und packe Inventare...
|
||||
GDPR_STATUS_DATABASE=§7Packe Datenbankinhalte...
|
||||
GDPR_STATUS_LOGS=§7Suche und packe logs...
|
||||
GDPR_STATUS_FINISHED=§7Packen abgeschlossen
|
In neuem Issue referenzieren
Einen Benutzer sperren