#792 Add columns for registration IP and registration date

- Add columns for reg date and IP
- Rename "ip" to "last IP"
This commit is contained in:
ljacqu
2017-10-14 17:37:34 +02:00
parent 1487fc0d9e
commit 52d6476058
37 changed files with 362 additions and 235 deletions
@@ -178,6 +178,7 @@ public class NewAPI {
.name(name)
.password(result)
.realName(playerName)
.registrationDate(System.currentTimeMillis())
.build();
return dataSource.saveAuth(auth);
}
@@ -128,7 +128,7 @@ public class AuthMeApi {
* Get the last location of an online player.
*
* @param player The player to process
* @return Location The location of the player
* @return The location of the player
*/
public Location getLastLocation(Player player) {
PlayerAuth auth = playerCache.getAuth(player.getName());
@@ -143,7 +143,7 @@ public class AuthMeApi {
* Get the last ip address of a player.
*
* @param playerName The name of the player to process
* @return String The last ip address of the player
* @return The last ip address of the player
*/
public String getLastIp(String playerName) {
PlayerAuth auth = playerCache.getAuth(playerName);
@@ -151,7 +151,7 @@ public class AuthMeApi {
auth = dataSource.getAuth(playerName);
}
if (auth != null) {
return auth.getIp();
return auth.getLastIp();
}
return null;
}
@@ -160,7 +160,7 @@ public class AuthMeApi {
* Get user names by ip.
*
* @param address The ip address to process
* @return List The list of user names related to the ip address
* @return The list of user names related to the ip address
*/
public List<String> getNamesByIp(String address) {
return dataSource.getAllAuthsByIp(address);
@@ -170,11 +170,11 @@ public class AuthMeApi {
* Get the last login date of a player.
*
* @param playerName The name of the player to process
* @return Date The date of the last login
* @return The date of the last login, or null if the player doesn't exist or has never logged in
*/
public Date getLastLogin(String playerName) {
PlayerAuth auth = playerCache.getAuth(playerName);
if(auth == null) {
if (auth == null) {
auth = dataSource.getAuth(playerName);
}
if (auth != null) {
@@ -223,6 +223,7 @@ public class AuthMeApi {
.name(name)
.password(result)
.realName(playerName)
.registrationDate(System.currentTimeMillis())
.build();
return dataSource.saveAuth(auth);
}
@@ -54,7 +54,7 @@ public class AccountsCommand implements ExecutableCommand {
return;
}
List<String> accountList = dataSource.getAllAuthsByIp(auth.getIp());
List<String> accountList = dataSource.getAllAuthsByIp(auth.getLastIp());
if (accountList.isEmpty()) {
commonService.send(sender, MessageKey.UNKNOWN_USER);
} else if (accountList.size() == 1) {
@@ -1,7 +1,10 @@
package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -13,18 +16,26 @@ public class GetIpCommand implements ExecutableCommand {
@Inject
private BukkitService bukkitService;
@Inject
private DataSource dataSource;
@Override
public void executeCommand(CommandSender sender, List<String> arguments) {
// Get the player query
String playerName = arguments.get(0);
Player player = bukkitService.getPlayerExact(playerName);
if (player == null) {
sender.sendMessage("The player is not online");
return;
PlayerAuth auth = dataSource.getAuth(playerName);
if (player != null) {
sender.sendMessage("Current IP of " + player.getName() + " is " + PlayerUtils.getPlayerIp(player)
+ ":" + player.getAddress().getPort());
}
sender.sendMessage(player.getName() + "'s IP is: " + player.getAddress().getAddress().getHostAddress()
+ ":" + player.getAddress().getPort());
if (auth == null) {
String displayName = player == null ? playerName : player.getName();
sender.sendMessage(displayName + " is not registered in the database");
} else {
sender.sendMessage("Database: last IP: " + auth.getLastIp() + ", registration IP: "
+ auth.getRegistrationIp());
}
}
}
@@ -45,6 +45,6 @@ public class LastLoginCommand implements ExecutableCommand {
// Show the player status
sender.sendMessage("[AuthMe] " + playerName + " last login: " + date.toString());
sender.sendMessage("[AuthMe] The player " + playerName + " last logged in " + lastLoginMessage + " ago.");
sender.sendMessage("[AuthMe] Last Player's IP: " + auth.getIp());
sender.sendMessage("[AuthMe] Last Player's IP: " + auth.getLastIp());
}
}
@@ -64,6 +64,7 @@ public class RegisterAdminCommand implements ExecutableCommand {
.name(playerNameLowerCase)
.realName(playerName)
.password(hashedPassword)
.registrationDate(System.currentTimeMillis())
.build();
if (!dataSource.saveAuth(auth)) {
@@ -77,8 +77,8 @@ class CountryLookup implements DebugSection {
if (auth == null) {
sender.sendMessage("No player with name '" + name + "'");
} else {
sender.sendMessage("Player '" + name + "' has IP address " + auth.getIp());
outputInfoForIpAddr(sender, auth.getIp());
sender.sendMessage("Player '" + name + "' has IP address " + auth.getLastIp());
outputInfoForIpAddr(sender, auth.getLastIp());
}
}
}
@@ -65,10 +65,12 @@ class PlayerAuthViewer implements DebugSection {
*/
private void displayAuthToSender(PlayerAuth auth, CommandSender sender) {
sender.sendMessage(ChatColor.GOLD + "[AuthMe] Player " + auth.getNickname() + " / " + auth.getRealName());
sender.sendMessage("Email: " + auth.getEmail() + ". IP: " + auth.getIp() + ". Group: " + auth.getGroupId());
sender.sendMessage("Email: " + auth.getEmail() + ". IP: " + auth.getLastIp() + ". Group: " + auth.getGroupId());
sender.sendMessage("Quit location: "
+ formatLocation(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld()));
sender.sendMessage("Last login: " + formatLastLogin(auth));
sender.sendMessage("Last login: " + formatDate(auth.getLastLogin()));
sender.sendMessage("Registration: " + formatDate(auth.getRegistrationDate())
+ " with IP " + auth.getRegistrationIp());
HashedPassword hashedPass = auth.getPassword();
sender.sendMessage("Hash / salt (partial): '" + safeSubstring(hashedPass.getHash(), 6)
@@ -94,17 +96,18 @@ class PlayerAuthViewer implements DebugSection {
}
/**
* Formats the last login date from the given PlayerAuth.
* Formats the given timestamp to a human readable date.
*
* @param auth the auth object
* @return the last login as human readable date
* @param timestamp the timestamp to format (nullable)
* @return the formatted timestamp
*/
private static String formatLastLogin(PlayerAuth auth) {
long lastLogin = auth.getLastLogin();
if (lastLogin == 0) {
return "Never (0)";
private static String formatDate(Long timestamp) {
if (timestamp == null) {
return "Not available (null)";
} else if (timestamp == 0) {
return "Not available (0)";
} else {
LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastLogin), ZoneId.systemDefault());
LocalDateTime date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(date);
}
}
@@ -3,6 +3,8 @@ package fr.xephi.authme.data.auth;
import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.Location;
import java.util.Objects;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -18,9 +20,11 @@ public class PlayerAuth {
private String realName;
private HashedPassword password;
private String email;
private String ip;
private String lastIp;
private int groupId;
private long lastLogin;
private String registrationIp;
private long registrationDate;
// Fields storing the player's quit location
private double x;
private double y;
@@ -29,13 +33,6 @@ public class PlayerAuth {
private float yaw;
private float pitch;
/**
* @param serialized String
*/
public PlayerAuth(String serialized) {
this.deserialize(serialized);
}
/**
* Hidden constructor.
*
@@ -112,12 +109,12 @@ public class PlayerAuth {
return pitch;
}
public String getIp() {
return ip;
public String getLastIp() {
return lastIp;
}
public void setIp(String ip) {
this.ip = ip;
public void setLastIp(String lastIp) {
this.lastIp = lastIp;
}
public long getLastLogin() {
@@ -144,76 +141,45 @@ public class PlayerAuth {
this.password = password;
}
public String getRegistrationIp() {
return registrationIp;
}
public long getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(long registrationDate) {
this.registrationDate = registrationDate;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PlayerAuth)) {
return false;
}
PlayerAuth other = (PlayerAuth) obj;
return other.getIp().equals(this.ip) && other.getNickname().equals(this.nickname);
return Objects.equals(other.lastIp, this.lastIp) && Objects.equals(other.nickname, this.nickname);
}
@Override
public int hashCode() {
int hashCode = 7;
hashCode = 71 * hashCode + (this.nickname != null ? this.nickname.hashCode() : 0);
hashCode = 71 * hashCode + (this.ip != null ? this.ip.hashCode() : 0);
hashCode = 71 * hashCode + (this.lastIp != null ? this.lastIp.hashCode() : 0);
return hashCode;
}
@Override
public String toString() {
return "Player : " + nickname + " | " + realName
+ " ! IP : " + ip
+ " ! IP : " + lastIp
+ " ! LastLogin : " + lastLogin
+ " ! LastPosition : " + x + "," + y + "," + z + "," + world
+ " ! Email : " + email
+ " ! Password : {" + password.getHash() + ", " + password.getSalt() + "}";
}
/**
* Method to serialize PlayerAuth
*
* @return String
*/
public String serialize() {
StringBuilder str = new StringBuilder();
char d = ';';
str.append(this.nickname).append(d);
str.append(this.realName).append(d);
str.append(this.ip).append(d);
str.append(this.email).append(d);
str.append(this.password.getHash()).append(d);
str.append(this.password.getSalt()).append(d);
str.append(this.groupId).append(d);
str.append(this.lastLogin).append(d);
str.append(this.world).append(d);
str.append(this.x).append(d);
str.append(this.y).append(d);
str.append(this.z);
return str.toString();
}
/**
* Method to deserialize PlayerAuth
*
* @param str String
*/
public void deserialize(String str) {
String[] args = str.split(";");
this.nickname = args[0];
this.realName = args[1];
this.ip = args[2];
this.email = args[3];
this.password = new HashedPassword(args[4], args[5]);
this.groupId = Integer.parseInt(args[6]);
this.lastLogin = Long.parseLong(args[7]);
this.world = args[8];
this.x = Double.parseDouble(args[9]);
this.y = Double.parseDouble(args[10]);
this.z = Double.parseDouble(args[11]);
}
public static Builder builder() {
return new Builder();
}
@@ -222,10 +188,12 @@ public class PlayerAuth {
private String name;
private String realName;
private HashedPassword password;
private String ip;
private String lastIp;
private String email;
private int groupId = -1;
private long lastLogin = System.currentTimeMillis();
private String registrationIp;
private Long registrationDate;
private double x;
private double y;
@@ -245,9 +213,11 @@ public class PlayerAuth {
auth.realName = firstNonNull(realName, "Player");
auth.password = firstNonNull(password, new HashedPassword(""));
auth.email = firstNonNull(email, "your@email.com");
auth.ip = firstNonNull(ip, "127.0.0.1");
auth.lastIp = firstNonNull(lastIp, "127.0.0.1");
auth.groupId = groupId;
auth.lastLogin = lastLogin;
auth.registrationIp = registrationIp;
auth.registrationDate = registrationDate == null ? System.currentTimeMillis() : registrationDate;
auth.x = x;
auth.y = y;
@@ -277,8 +247,8 @@ public class PlayerAuth {
return password(new HashedPassword(hash, salt));
}
public Builder ip(String ip) {
this.ip = ip;
public Builder lastIp(String lastIp) {
this.lastIp = lastIp;
return this;
}
@@ -342,5 +312,15 @@ public class PlayerAuth {
this.email = email;
return this;
}
public Builder registrationIp(String ip) {
this.registrationIp = ip;
return this;
}
public Builder registrationDate(long date) {
this.registrationDate = date;
return this;
}
}
}
@@ -14,7 +14,7 @@ public final class Columns {
public final String REAL_NAME;
public final String PASSWORD;
public final String SALT;
public final String IP;
public final String LAST_IP;
public final String LAST_LOGIN;
public final String GROUP;
public final String LASTLOC_X;
@@ -26,24 +26,28 @@ public final class Columns {
public final String EMAIL;
public final String ID;
public final String IS_LOGGED;
public final String REGISTRATION_DATE;
public final String REGISTRATION_IP;
public Columns(Settings settings) {
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD);
SALT = settings.getProperty(DatabaseSettings.MYSQL_COL_SALT);
IP = settings.getProperty(DatabaseSettings.MYSQL_COL_IP);
LAST_LOGIN = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOGIN);
GROUP = settings.getProperty(DatabaseSettings.MYSQL_COL_GROUP);
LASTLOC_X = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_X);
LASTLOC_Y = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Y);
LASTLOC_Z = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Z);
LASTLOC_WORLD = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_WORLD);
LASTLOC_YAW = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_YAW);
LASTLOC_PITCH = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_PITCH);
EMAIL = settings.getProperty(DatabaseSettings.MYSQL_COL_EMAIL);
ID = settings.getProperty(DatabaseSettings.MYSQL_COL_ID);
IS_LOGGED = settings.getProperty(DatabaseSettings.MYSQL_COL_ISLOGGED);
NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME);
REAL_NAME = settings.getProperty(DatabaseSettings.MYSQL_COL_REALNAME);
PASSWORD = settings.getProperty(DatabaseSettings.MYSQL_COL_PASSWORD);
SALT = settings.getProperty(DatabaseSettings.MYSQL_COL_SALT);
LAST_IP = settings.getProperty(DatabaseSettings.MYSQL_COL_LAST_IP);
LAST_LOGIN = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOGIN);
GROUP = settings.getProperty(DatabaseSettings.MYSQL_COL_GROUP);
LASTLOC_X = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_X);
LASTLOC_Y = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Y);
LASTLOC_Z = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_Z);
LASTLOC_WORLD = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_WORLD);
LASTLOC_YAW = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_YAW);
LASTLOC_PITCH = settings.getProperty(DatabaseSettings.MYSQL_COL_LASTLOC_PITCH);
EMAIL = settings.getProperty(DatabaseSettings.MYSQL_COL_EMAIL);
ID = settings.getProperty(DatabaseSettings.MYSQL_COL_ID);
IS_LOGGED = settings.getProperty(DatabaseSettings.MYSQL_COL_ISLOGGED);
REGISTRATION_DATE = settings.getProperty(DatabaseSettings.MYSQL_COL_REGISTER_DATE);
REGISTRATION_IP = settings.getProperty(DatabaseSettings.MYSQL_COL_REGISTER_IP);
}
}
@@ -79,7 +79,7 @@ public class FlatFile implements DataSource {
return false;
}
try (BufferedWriter bw = new BufferedWriter(new FileWriter(source, true))) {
bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getIp()
bw.write(auth.getNickname() + ":" + auth.getPassword().getHash() + ":" + auth.getLastIp()
+ ":" + auth.getLastLogin() + ":" + auth.getQuitLocX() + ":" + auth.getQuitLocY()
+ ":" + auth.getQuitLocZ() + ":" + auth.getWorld() + ":" + auth.getEmail() + "\n");
} catch (IOException ex) {
@@ -139,7 +139,7 @@ public class FlatFile implements DataSource {
newAuth = buildAuthFromArray(args);
if (newAuth != null) {
newAuth.setLastLogin(auth.getLastLogin());
newAuth.setIp(auth.getIp());
newAuth.setLastIp(auth.getLastIp());
}
break;
}
@@ -393,7 +393,7 @@ public class FlatFile implements DataSource {
PlayerAuth.Builder builder = PlayerAuth.builder()
.name(args[0]).realName(args[0]).password(args[1], null);
if (args.length >= 3) builder.ip(args[2]);
if (args.length >= 3) builder.lastIp(args[2]);
if (args.length >= 4) builder.lastLogin(Long.parseLong(args[3]));
if (args.length >= 7) {
builder.locX(Double.parseDouble(args[4]))
@@ -189,9 +189,9 @@ public class MySQL implements DataSource {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
}
if (isColumnMissing(md, col.IP)) {
if (isColumnMissing(md, col.LAST_IP)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
+ " ADD COLUMN " + col.LAST_IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL;");
}
if (isColumnMissing(md, col.LAST_LOGIN)) {
@@ -201,6 +201,16 @@ public class MySQL implements DataSource {
migrateLastLoginColumn(con, md);
}
if (isColumnMissing(md, col.REGISTRATION_DATE)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.REGISTRATION_DATE + " BIGINT;");
}
if (isColumnMissing(md, col.REGISTRATION_IP)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.REGISTRATION_IP + " VARCHAR(40) CHARACTER SET ascii COLLATE ascii_bin;");
}
if (isColumnMissing(md, col.LASTLOC_X)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN "
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0' AFTER " + col.LAST_LOGIN + " , ADD "
@@ -305,20 +315,19 @@ public class MySQL implements DataSource {
public boolean saveAuth(PlayerAuth auth) {
try (Connection con = getConnection()) {
String sql;
boolean useSalt = !col.SALT.isEmpty() || !StringUtils.isEmpty(auth.getPassword().getSalt());
sql = "INSERT INTO " + tableName + "("
+ col.NAME + "," + col.PASSWORD + "," + col.IP + ","
+ col.LAST_LOGIN + "," + col.REAL_NAME + "," + col.EMAIL
+ col.NAME + "," + col.PASSWORD + "," + col.REAL_NAME
+ "," + col.EMAIL + "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP
+ (useSalt ? "," + col.SALT : "")
+ ") VALUES (?,?,?,?,?,?" + (useSalt ? ",?" : "") + ");";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getNickname());
pst.setString(2, auth.getPassword().getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
pst.setString(6, auth.getEmail());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getEmail());
pst.setObject(5, auth.getRegistrationDate());
pst.setString(6, auth.getRegistrationIp());
if (useSalt) {
pst.setString(7, auth.getPassword().getSalt());
}
@@ -382,9 +391,9 @@ public class MySQL implements DataSource {
@Override
public boolean updateSession(PlayerAuth auth) {
String sql = "UPDATE " + tableName + " SET "
+ col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
+ col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getIp());
pst.setString(1, auth.getLastIp());
pst.setLong(2, auth.getLastLogin());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getNickname());
@@ -479,7 +488,7 @@ public class MySQL implements DataSource {
@Override
public List<String> getAllAuthsByIp(String ip) {
List<String> result = new ArrayList<>();
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
try (ResultSet rs = pst.executeQuery()) {
@@ -665,15 +674,17 @@ public class MySQL implements DataSource {
.realName(row.getString(col.REAL_NAME))
.password(row.getString(col.PASSWORD), salt)
.lastLogin(row.getLong(col.LAST_LOGIN))
.ip(row.getString(col.IP))
.lastIp(row.getString(col.LAST_IP))
.email(row.getString(col.EMAIL))
.registrationDate(row.getLong(col.REGISTRATION_DATE))
.registrationIp(row.getString(col.REGISTRATION_IP))
.groupId(group)
.locWorld(row.getString(col.LASTLOC_WORLD))
.locX(row.getDouble(col.LASTLOC_X))
.locY(row.getDouble(col.LASTLOC_Y))
.locZ(row.getDouble(col.LASTLOC_Z))
.locYaw(row.getFloat(col.LASTLOC_YAW))
.locPitch(row.getFloat(col.LASTLOC_PITCH))
.email(row.getString(col.EMAIL))
.groupId(group)
.build();
}
@@ -706,6 +717,7 @@ public class MySQL implements DataSource {
* Performs conversion of lastlogin column from timestamp type to bigint.
*
* @param con connection to the database
* @see <a href="https://github.com/AuthMe/AuthMeReloaded/issues/477">#477</a>
*/
private void migrateLastLoginColumnFromTimestamp(Connection con) throws SQLException {
ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
@@ -721,7 +733,7 @@ public class MySQL implements DataSource {
// Create lastlogin column
sql = String.format("ALTER TABLE %s ADD COLUMN %s "
+ "BIGINT NOT NULL DEFAULT 0 AFTER %s",
tableName, col.LAST_LOGIN, col.IP);
tableName, col.LAST_LOGIN, col.LAST_IP);
con.prepareStatement(sql).execute();
// Set values of lastlogin based on lastlogin_old
@@ -740,6 +752,8 @@ public class MySQL implements DataSource {
* Performs conversion of lastlogin column from int to bigint.
*
* @param con connection to the database
* @see <a href="https://github.com/AuthMe/AuthMeReloaded/issues/887">
* #887: Migrate lastlogin column from int32 to bigint</a>
*/
private void migrateLastLoginColumnFromInt(Connection con) throws SQLException {
// Change from int to bigint
@@ -94,9 +94,9 @@ public class SQLite implements DataSource {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.SALT + " VARCHAR(255);");
}
if (isColumnMissing(md, col.IP)) {
if (isColumnMissing(md, col.LAST_IP)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.IP + " VARCHAR(40) NOT NULL DEFAULT '';");
+ " ADD COLUMN " + col.LAST_IP + " VARCHAR(40) NOT NULL DEFAULT '';");
}
if (isColumnMissing(md, col.LAST_LOGIN)) {
@@ -104,6 +104,16 @@ public class SQLite implements DataSource {
+ " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP;");
}
if (isColumnMissing(md, col.REGISTRATION_IP)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.REGISTRATION_IP + " VARCHAR(40);");
}
if (isColumnMissing(md, col.REGISTRATION_DATE)) {
st.executeUpdate("ALTER TABLE " + tableName
+ " ADD COLUMN " + col.REGISTRATION_DATE + " TIMESTAMP NOT NULL DEFAULT '0';");
}
if (isColumnMissing(md, col.LASTLOC_X)) {
st.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN " + col.LASTLOC_X
+ " DOUBLE NOT NULL DEFAULT '0.0';");
@@ -209,6 +219,7 @@ public class SQLite implements DataSource {
@Override
public boolean saveAuth(PlayerAuth auth) {
PreparedStatement pst = null;
try {
HashedPassword password = auth.getPassword();
if (col.SALT.isEmpty()) {
@@ -216,33 +227,36 @@ public class SQLite implements DataSource {
ConsoleLogger.warning("Warning! Detected hashed password with separate salt but the salt column "
+ "is not set in the config!");
}
try (PreparedStatement pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD +
"," + col.IP + "," + col.LAST_LOGIN + "," + col.REAL_NAME + "," + col.EMAIL +
") VALUES (?,?,?,?,?,?);")) {
pst.setString(1, auth.getNickname());
pst.setString(2, password.getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
pst.setString(6, auth.getEmail());
pst.executeUpdate();
}
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD
+ "," + col.REAL_NAME + "," + col.EMAIL
+ "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP
+ ") VALUES (?,?,?,?,?,?);");
pst.setString(1, auth.getNickname());
pst.setString(2, password.getHash());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getEmail());
pst.setLong(5, auth.getRegistrationDate());
pst.setString(6, auth.getRegistrationIp());
pst.executeUpdate();
} else {
try (PreparedStatement pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD + ","
+ col.IP + "," + col.LAST_LOGIN + "," + col.REAL_NAME + "," + col.EMAIL + "," + col.SALT
+ ") VALUES (?,?,?,?,?,?,?);")) {
pst.setString(1, auth.getNickname());
pst.setString(2, password.getHash());
pst.setString(3, auth.getIp());
pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
pst.setString(6, auth.getEmail());
pst.setString(7, password.getSalt());
pst.executeUpdate();
}
pst = con.prepareStatement("INSERT INTO " + tableName + "(" + col.NAME + "," + col.PASSWORD
+ "," + col.REAL_NAME + "," + col.EMAIL
+ "," + col.REGISTRATION_DATE + "," + col.REGISTRATION_IP + "," + col.SALT
+ ") VALUES (?,?,?,?,?,?,?);");
pst.setString(1, auth.getNickname());
pst.setString(2, password.getHash());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getEmail());
pst.setLong(5, auth.getRegistrationDate());
pst.setString(6, auth.getRegistrationIp());
pst.setString(7, password.getSalt());
pst.executeUpdate();
}
} catch (SQLException ex) {
logSqlException(ex);
} finally {
close(pst);
}
return true;
}
@@ -277,9 +291,10 @@ public class SQLite implements DataSource {
@Override
public boolean updateSession(PlayerAuth auth) {
String sql = "UPDATE " + tableName + " SET " + col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
String sql = "UPDATE " + tableName + " SET " + col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, "
+ col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)){
pst.setString(1, auth.getIp());
pst.setString(1, auth.getLastIp());
pst.setLong(2, auth.getLastLogin());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getNickname());
@@ -388,7 +403,7 @@ public class SQLite implements DataSource {
@Override
public List<String> getAllAuthsByIp(String ip) {
List<String> countIp = new ArrayList<>();
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;";
try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
try (ResultSet rs = pst.executeQuery()) {
@@ -554,27 +569,24 @@ public class SQLite implements DataSource {
private PlayerAuth buildAuthFromResultSet(ResultSet row) throws SQLException {
String salt = !col.SALT.isEmpty() ? row.getString(col.SALT) : null;
PlayerAuth.Builder authBuilder = PlayerAuth.builder()
return PlayerAuth.builder()
.name(row.getString(col.NAME))
.email(row.getString(col.EMAIL))
.realName(row.getString(col.REAL_NAME))
.password(row.getString(col.PASSWORD), salt)
.lastLogin(row.getLong(col.LAST_LOGIN))
.lastIp(row.getString(col.LAST_IP))
.registrationDate(row.getLong(col.REGISTRATION_DATE))
.registrationIp(row.getString(col.REGISTRATION_IP))
.locX(row.getDouble(col.LASTLOC_X))
.locY(row.getDouble(col.LASTLOC_Y))
.locZ(row.getDouble(col.LASTLOC_Z))
.locWorld(row.getString(col.LASTLOC_WORLD))
.locYaw(row.getFloat(col.LASTLOC_YAW))
.locPitch(row.getFloat(col.LASTLOC_PITCH));
String ip = row.getString(col.IP);
if (!ip.isEmpty()) {
authBuilder.ip(ip);
}
return authBuilder.build();
.locPitch(row.getFloat(col.LASTLOC_PITCH))
.build();
}
private static void close(Statement st) {
if (st != null) {
try {
@@ -2,6 +2,7 @@ package fr.xephi.authme.datasource;
import fr.xephi.authme.ConsoleLogger;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
@@ -20,4 +21,18 @@ final class SqlDataSourceUtils {
static void logSqlException(SQLException e) {
ConsoleLogger.logException("Error during SQL operation:", e);
}
/**
* Returns the long value of a column, or null when appropriate. This method is necessary because
* JDBC's {@link ResultSet#getLong} returns {@code 0} if the entry in the database is {@code null}.
*
* @param rs the result set to read from
* @param columnName the name of the column to retrieve
* @return the value (which may be null)
* @throws SQLException :)
*/
static Long getNullableLong(ResultSet rs, String columnName) throws SQLException {
long longValue = rs.getLong(columnName);
return rs.wasNull() ? null : longValue;
}
}
@@ -62,6 +62,7 @@ public abstract class AbstractDataSourceConverter<S extends DataSource> implemen
} else {
adaptPlayerAuth(auth);
destination.saveAuth(auth);
destination.updateSession(auth);
destination.updateQuitLoc(auth);
}
}
@@ -18,6 +18,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@@ -94,6 +95,7 @@ public class LoginSecurityConverter implements Converter {
} else {
PlayerAuth auth = buildAuthFromLoginSecurity(name, resultSet);
dataSource.saveAuth(auth);
dataSource.updateSession(auth);
++successfulSaves;
}
}
@@ -113,16 +115,17 @@ public class LoginSecurityConverter implements Converter {
* @return the created player auth object
*/
private static PlayerAuth buildAuthFromLoginSecurity(String name, ResultSet resultSet) throws SQLException {
// TODO #792: Last login should be null if not present
long lastLoginMillis = Optional.ofNullable(resultSet.getTimestamp("last_login"))
.map(Timestamp::getTime).orElse(System.currentTimeMillis());
Long lastLoginMillis = Optional.ofNullable(resultSet.getTimestamp("last_login"))
.map(Timestamp::getTime).orElse(null);
long regDate = Optional.ofNullable(resultSet.getDate("registration_date"))
.map(Date::getTime).orElse(System.currentTimeMillis());
return PlayerAuth.builder()
.name(name)
.realName(name)
.password(resultSet.getString("password"), null)
.ip(resultSet.getString("ip_address"))
.lastIp(resultSet.getString("ip_address"))
.lastLogin(lastLoginMillis)
// TODO #792: Register date
.registrationDate(regDate)
.locX(resultSet.getDouble("x"))
.locY(resultSet.getDouble("y"))
.locZ(resultSet.getDouble("z"))
@@ -80,11 +80,11 @@ public class RakamakConverter implements Converter {
PlayerAuth auth = PlayerAuth.builder()
.name(playerName)
.realName(playerName)
.ip(ip)
.lastIp(ip)
.password(psw)
.lastLogin(0)
.build();
database.saveAuth(auth);
database.updateSession(auth);
}
Utils.logAndSendMessage(sender, "Rakamak database has been imported correctly");
} catch (IOException ex) {
@@ -46,6 +46,7 @@ public class RoyalAuthConverter implements Converter {
.build();
dataSource.saveAuth(auth);
dataSource.updateSession(auth);
} catch (Exception e) {
ConsoleLogger.logException("Error while trying to import " + player.getName() + " RoyalAuth data", e);
}
@@ -188,7 +188,7 @@ public class AsynchronousJoin implements AsynchronousProcess {
long timeSinceLastLogin = System.currentTimeMillis() - auth.getLastLogin();
if(timeSinceLastLogin < 0
|| timeSinceLastLogin > (service.getProperty(PluginSettings.SESSIONS_TIMEOUT) * 60 * 1000)
|| !auth.getIp().equals(PlayerUtils.getPlayerIp(player))) {
|| !auth.getLastIp().equals(PlayerUtils.getPlayerIp(player))) {
service.send(player, MessageKey.SESSION_EXPIRED);
} else {
RestoreSessionEvent event = bukkitService.createAndCallEvent(
@@ -215,7 +215,7 @@ public class AsynchronousLogin implements AsynchronousProcess {
final String ip = PlayerUtils.getPlayerIp(player);
auth.setRealName(player.getName());
auth.setLastLogin(System.currentTimeMillis());
auth.setIp(ip);
auth.setLastIp(ip);
dataSource.updateSession(auth);
// Successful login, so reset the captcha & temp ban count
@@ -227,8 +227,8 @@ public class AsynchronousLogin implements AsynchronousProcess {
service.send(player, MessageKey.LOGIN_SUCCESS);
// Other auths
List<String> auths = dataSource.getAllAuthsByIp(auth.getIp());
runCommandOtherAccounts(auths, player, auth.getIp());
List<String> auths = dataSource.getAllAuthsByIp(auth.getLastIp());
runCommandOtherAccounts(auths, player, auth.getLastIp());
displayOtherAccounts(auths, player);
final String email = auth.getEmail();
@@ -72,7 +72,7 @@ public class AsynchronousQuit implements AsynchronousProcess {
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
.ip(ip)
.lastIp(ip)
.lastLogin(System.currentTimeMillis())
.build();
database.updateSession(auth);
@@ -27,8 +27,8 @@ final class PlayerAuthBuilderHelper {
.realName(player.getName())
.password(hashedPassword)
.email(email)
.ip(PlayerUtils.getPlayerIp(player))
.location(player.getLocation())
.registrationIp(PlayerUtils.getPlayerIp(player))
.registrationDate(System.currentTimeMillis())
.build();
}
}
@@ -75,14 +75,22 @@ public final class DatabaseSettings implements SettingsHolder {
public static final Property<String> MYSQL_COL_ISLOGGED =
newProperty("DataSource.mySQLColumnLogged", "isLogged");
@Comment("Column for storing players ips")
public static final Property<String> MYSQL_COL_IP =
@Comment("Column for storing the player's last IP")
public static final Property<String> MYSQL_COL_LAST_IP =
newProperty("DataSource.mySQLColumnIp", "ip");
@Comment("Column for storing players lastlogins")
public static final Property<String> MYSQL_COL_LASTLOGIN =
newProperty("DataSource.mySQLColumnLastLogin", "lastlogin");
@Comment("Column storing the registration date")
public static final Property<String> MYSQL_COL_REGISTER_DATE =
newProperty("DataSource.mySQLColumnRegisterDate", "regdate");
@Comment("Column for storing the IP address at the time of registration")
public static final Property<String> MYSQL_COL_REGISTER_IP =
newProperty("DataSource.mySQLColumnRegisterIp", "regip");
@Comment("Column for storing player LastLocation - X")
public static final Property<String> MYSQL_COL_LASTLOC_X =
newProperty("DataSource.mySQLlastlocX", "x");