Merge branch 'master' into RemoveCommandFramework
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Dieser Commit ist enthalten in:
yoyosource 2024-03-23 11:11:02 +01:00
Commit 7ecff22b6d
7 geänderte Dateien mit 151 neuen und 6 gelöschten Zeilen

Datei anzeigen

@ -87,6 +87,7 @@ public class Event {
private final SchematicType schemType; private final SchematicType schemType;
@Field @Field
private final boolean publicSchemsOnly; private final boolean publicSchemsOnly;
@Deprecated
@Field @Field
private final boolean spectateSystem; private final boolean spectateSystem;

Datei anzeigen

@ -84,8 +84,12 @@ public class EventFight implements Comparable<EventFight> {
private final int teamRed; private final int teamRed;
@Getter @Getter
@Field @Field
@Deprecated
private final int kampfleiter; private final int kampfleiter;
@Getter @Getter
@Field
private final int spectatePort;
@Getter
@Field(def = "0") @Field(def = "0")
private int ergebnis; private int ergebnis;
@Field(nullable = true) @Field(nullable = true)

Datei anzeigen

@ -0,0 +1,44 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import java.util.Set;
import java.util.stream.Collectors;
@AllArgsConstructor
public class Referee {
private static final Table<Referee> table = new Table<>(Referee.class);
private static final SelectStatement<Referee> byEvent = table.selectFields("eventID");
public static Set<Integer> get(int eventID) {
return byEvent.listSelect(eventID).stream().map(referee -> referee.userID).collect(Collectors.toSet());
}
@Field(keys = {"eventReferee"})
private final int eventID;
@Field(keys = {"eventReferee"})
private final int userID;
}

Datei anzeigen

@ -56,7 +56,7 @@ public class SchematicNode {
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName"); private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?"); private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?"); private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?");
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSASN AS (WITH RSAN AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSA WHERE RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN INNER JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSASN WHERE SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN INNER JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "?"); private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?"); private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?"); private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId"); private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");

Datei anzeigen

@ -21,17 +21,32 @@ package de.steamwar.sql;
import de.steamwar.sql.internal.*; import de.steamwar.sql.internal.*;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SteamwarUser { public class SteamwarUser {
private static final SecureRandom random = new SecureRandom();
private static final SecretKeyFactory factory;
static { static {
new SqlTypeMapper<>(UUID.class, "CHAR(36)", (rs, identifier) -> UUID.fromString(rs.getString(identifier)), (st, index, value) -> st.setString(index, value.toString())); try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
}
new SqlTypeMapper<>(UUID.class, "CHAR(36)", (rs, identifier) -> UUID.fromString(rs.getString(identifier)), (st, index, value) -> st.setString(index, value.toString()));
new SqlTypeMapper<>(Locale.class, "VARCHAR(32)", (rs, identifier) -> { new SqlTypeMapper<>(Locale.class, "VARCHAR(32)", (rs, identifier) -> {
String l = rs.getString(identifier); String l = rs.getString(identifier);
return l != null ? Locale.forLanguageTag(l) : null; return l != null ? Locale.forLanguageTag(l) : null;
@ -49,6 +64,7 @@ public class SteamwarUser {
private static final SelectStatement<SteamwarUser> getServerTeam = new SelectStatement<>(table, "SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'"); private static final SelectStatement<SteamwarUser> getServerTeam = new SelectStatement<>(table, "SELECT * FROM UserData WHERE UserGroup != 'Member' AND UserGroup != 'YouTuber'");
private static final Statement updateName = table.update(Table.PRIMARY, "UserName"); private static final Statement updateName = table.update(Table.PRIMARY, "UserName");
private static final Statement updatePassword = table.update(Table.PRIMARY, "Password");
private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale"); private static final Statement updateLocale = table.update(Table.PRIMARY, "Locale", "ManualLocale");
private static final Statement updateTeam = table.update(Table.PRIMARY, "Team"); private static final Statement updateTeam = table.update(Table.PRIMARY, "Team");
private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader"); private static final Statement updateLeader = table.update(Table.PRIMARY, "Leader");
@ -110,7 +126,7 @@ public class SteamwarUser {
if (user != null) { if (user != null) {
if (!user.userName.equals(name)) { if (!user.userName.equals(name)) {
updateName.update(name, user.id); updateName.update(name, user.id);
nameUpdate.accept(user.userName, name); nameUpdate.accept(user.userName, name);
user.userName = name; user.userName = name;
} }
@ -148,7 +164,9 @@ public class SteamwarUser {
@Getter @Getter
@Field @Field
private String userName; private String userName;
@Getter @Field(nullable = true)
private String password;
@Getter
@Field(def = "0") @Field(def = "0")
private int team; private int team;
@Getter @Getter
@ -166,10 +184,11 @@ public class SteamwarUser {
private Set<UserPerm> permissions = null; private Set<UserPerm> permissions = null;
private UserPerm.Prefix prefix = null; private UserPerm.Prefix prefix = null;
public SteamwarUser(int id, UUID uuid, String userName, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) { public SteamwarUser(int id, UUID uuid, String userName, String password, int team, boolean leader, Locale locale, boolean manualLocale, Long discordId) {
this.id = id; this.id = id;
this.uuid = uuid; this.uuid = uuid;
this.userName = userName; this.userName = userName;
this.password = password;
this.team = team; this.team = team;
this.leader = leader; this.leader = leader;
this.locale = locale; this.locale = locale;
@ -280,6 +299,52 @@ public class SteamwarUser {
} }
} }
public void setPassword(String password) {
try {
byte[] salt = new byte[16];
random.nextBytes(salt);
String saltString = Base64.getEncoder().encodeToString(salt);
byte[] hash = generateHash(password, salt);
String hashString = Base64.getEncoder().encodeToString(hash);
this.password = hashString + ":" + saltString;
updatePassword.update(this.password, id);
} catch (Exception e) {
throw new SecurityException(e);
}
}
public boolean verifyPassword(String password) {
try {
if (this.password == null) {
return false;
}
String[] parts = this.password.split(":");
if (parts.length != 2) {
SQLConfig.impl.getLogger().log(Level.SEVERE ,"Invalid password hash for user {0} ({1})", new Object[]{userName, id});
return false;
}
String hashString = parts[0];
byte[] realHash = Base64.getDecoder().decode(hashString);
String saltString = parts[1];
byte[] salt = Base64.getDecoder().decode(saltString);
byte[] hash = generateHash(password, salt);
return Arrays.equals(realHash, hash);
} catch (Exception e) {
SQLConfig.impl.getLogger().log(Level.SEVERE, "Error while verifying password for user " + userName + " (" + id + ")", e);
return false;
}
}
private byte[] generateHash(String password, byte[] salt)
throws InvalidKeySpecException {
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 512);
return factory.generateSecret(spec).getEncoded();
}
private void initPunishments() { private void initPunishments() {
if(punishments != null) if(punishments != null)
return; return;

Datei anzeigen

@ -25,9 +25,13 @@ import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table; import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.SneakyThrows;
import lombok.ToString; import lombok.ToString;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Base64;
import java.util.List; import java.util.List;
@AllArgsConstructor @AllArgsConstructor
@ -41,6 +45,29 @@ public class Token {
private static final SelectStatement<Token> getHash = table.selectFields("hash"); private static final SelectStatement<Token> getHash = table.selectFields("hash");
private static final Statement delete = table.delete(Table.PRIMARY); private static final Statement delete = table.delete(Table.PRIMARY);
@SneakyThrows
private static String getHash(String code) {
return Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-512").digest(code.getBytes()));
}
@SneakyThrows
public static String createToken(String name, SteamwarUser owner) {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[20];
random.nextBytes(bytes);
String code = Base64.getEncoder().encodeToString(bytes);
String hash = getHash(code);
create(name, owner, hash);
return code;
}
public static Token getTokenByCode(String code) {
String hash = getHash(code);
return get(hash);
}
public static Token create(String name, SteamwarUser owner, String hash) { public static Token create(String name, SteamwarUser owner, String hash) {
int id = insert.insertGetKey(name, owner, hash); int id = insert.insertGetKey(name, owner, hash);
return get(id); return get(id);

Datei anzeigen

@ -134,7 +134,11 @@ public class Statement implements AutoCloseable {
public <T> T select(ResultSetUser<T> user, Object... objects) { public <T> T select(ResultSetUser<T> user, Object... objects) {
return withConnection(st -> { return withConnection(st -> {
ResultSet rs = st.executeQuery(); boolean res = st.execute();
if(!res) {
throw new SecurityException("No result set for select statement");
}
ResultSet rs = st.getResultSet();
T result = user.use(rs); T result = user.use(rs);
rs.close(); rs.close();
return result; return result;