diff --git a/README.md b/README.md
index c862068f..ff0b7f4d 100644
--- a/README.md
+++ b/README.md
@@ -122,7 +122,7 @@ typing commands or using the inventory. It can also kick players with uncommonly
Website Integration
Click here for an example of the Config file
How to convert from Rakamak
-Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /converter
+Convert from FlatFile (auths.db but not the sqlite one) to MySQL: /authme converter
diff --git a/pom.xml b/pom.xml
index 0ed8714c..e5d70cd1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -372,7 +372,7 @@
org.slf4j
slf4j-jdk14
- 1.7.14
+ 1.7.16
compile
true
@@ -400,7 +400,7 @@
com.google.code.gson
gson
- 2.5
+ 2.6.1
compile
true
@@ -416,9 +416,9 @@
- com.maxmind.geoip2
- geoip2
- 2.6.0
+ com.maxmind.geoip
+ geoip-api
+ 1.3.1
compile
true
diff --git a/samples/website_integration/bcrypt/form.php b/samples/website_integration/bcrypt/form.php
new file mode 100644
index 00000000..7801be4d
--- /dev/null
+++ b/samples/website_integration/bcrypt/form.php
@@ -0,0 +1,86 @@
+
+
+
+
+ AuthMe Integration Sample
+
+
+
+Login sample
+This is a demo form for AuthMe website integration. Enter your AuthMe login details
+into the following form to test it.
+';
+}
+
+function get_from_post_or_empty($index_name) {
+ return trim(
+ filter_input(INPUT_POST, $index_name, FILTER_UNSAFE_RAW, FILTER_REQUIRE_SCALAR | FILTER_FLAG_STRIP_LOW)
+ ?: '');
+}
+
+
+// Login logic
+function process_login($user, $pass) {
+ if (authme_check_password($user, $pass)) {
+ printf('Hello, %s!
', htmlspecialchars($user));
+ echo 'Successful login. Nice to have you back!'
+ . '
Back to form';
+ return true;
+ } else {
+ echo 'Error
Invalid username or password.';
+ }
+ return false;
+}
+
+// Register logic
+function process_register($user, $pass) {
+ if (authme_has_user($user)) {
+ echo 'Error
This user already exists.';
+ } else {
+ // Note that we don't validate the password or username at all in this demo...
+ $register_success = authme_register($user, $pass);
+ if ($register_success) {
+ printf('Welcome, %s!
Thanks for registering', htmlspecialchars($user));
+ echo '
Back to form';
+ return true;
+ } else {
+ echo 'Error
Unfortunately, there was an error during the registration.';
+ }
+ }
+ return false;
+}
+
+?>
+
+
+
diff --git a/samples/website_integration/bcrypt/integration.php b/samples/website_integration/bcrypt/integration.php
new file mode 100644
index 00000000..75911838
--- /dev/null
+++ b/samples/website_integration/bcrypt/integration.php
@@ -0,0 +1,107 @@
+prepare('SELECT password FROM ' . AUTHME_TABLE . ' WHERE username = ?');
+ $stmt->bind_param('s', $username);
+ $stmt->execute();
+ $stmt->bind_result($password);
+ if ($stmt->fetch()) {
+ return $password;
+ }
+ }
+ return null;
+}
+
+/**
+ * Returns whether the user exists in the database or not.
+ *
+ * @param string $username the username to check
+ * @return bool true if the user exists; false otherwise
+ */
+function authme_has_user($username) {
+ $mysqli = authme_get_mysqli();
+ if ($mysqli !== null) {
+ $stmt = $mysqli->prepare('SELECT 1 FROM ' . AUTHME_TABLE . ' WHERE username = ?');
+ $stmt->bind_param('s', $username);
+ $stmt->execute();
+ return $stmt->fetch();
+ }
+
+ // Defensive default to true; we actually don't know
+ return true;
+}
+
+/**
+ * Registers a player with the given username.
+ *
+ * @param string $username the username to register
+ * @param string $password the password to associate to the user
+ * @return bool whether or not the registration was successful
+ */
+function authme_register($username, $password) {
+ $mysqli = authme_get_mysqli();
+ if ($mysqli !== null) {
+ $hash = password_hash($password, PASSWORD_BCRYPT);
+ $stmt = $mysqli->prepare('INSERT INTO ' . AUTHME_TABLE . ' (username, realname, password, ip) '
+ . 'VALUES (?, ?, ?, ?)');
+ $username_low = strtolower($username);
+ $stmt->bind_param('ssss', $username, $username_low, $hash, $_SERVER['REMOTE_ADDR']);
+ return $stmt->execute();
+ }
+ return false;
+}
+
diff --git a/samples/website_integration/form.php b/samples/website_integration/sha256/form.php
similarity index 91%
rename from samples/website_integration/form.php
rename to samples/website_integration/sha256/form.php
index 5f2985cb..5ffecf34 100644
--- a/samples/website_integration/form.php
+++ b/samples/website_integration/sha256/form.php
@@ -1,5 +1,5 @@
@@ -36,7 +36,7 @@ into the following form to test it.
';
}
diff --git a/samples/website_integration/integration.php b/samples/website_integration/sha256/integration.php
similarity index 97%
rename from samples/website_integration/integration.php
rename to samples/website_integration/sha256/integration.php
index 3008fb98..e0de0bb1 100644
--- a/samples/website_integration/integration.php
+++ b/samples/website_integration/sha256/integration.php
@@ -1,6 +1,6 @@
baseCommands = ImmutableSet.of(
AUTHME_BASE,
LOGIN_BASE,
@@ -401,8 +400,7 @@ public final class CommandInitializer {
UNREGISTER_BASE,
CHANGE_PASSWORD_BASE,
EMAIL_BASE,
- CAPTCHA_BASE,
- CONVERTER_BASE);
+ CAPTCHA_BASE);
setHelpOnAllBases(baseCommands);
return baseCommands;
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
index 5d4d8cda..d3698cfd 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/AccountsCommand.java
@@ -30,7 +30,7 @@ public class AccountsCommand implements ExecutableCommand {
return;
}
- List accountList = commandService.getDataSource().getAllAuthsByName(auth);
+ List accountList = commandService.getDataSource().getAllAuthsByIp(auth.getIp());
if (accountList.isEmpty()) {
commandService.send(sender, MessageKey.USER_NOT_REGISTERED);
} else if (accountList.size() == 1) {
diff --git a/src/main/java/fr/xephi/authme/command/executable/converter/ConverterCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
similarity index 98%
rename from src/main/java/fr/xephi/authme/command/executable/converter/ConverterCommand.java
rename to src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
index cb3f6c7f..e3414480 100644
--- a/src/main/java/fr/xephi/authme/command/executable/converter/ConverterCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ConverterCommand.java
@@ -1,4 +1,4 @@
-package fr.xephi.authme.command.executable.converter;
+package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
diff --git a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
index 443e20ac..c87297d8 100644
--- a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
+++ b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java
@@ -7,8 +7,6 @@ import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
-import fr.xephi.authme.util.StringUtils;
-
import java.sql.SQLException;
/**
diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
index fd743289..4d0d4436 100644
--- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
@@ -115,24 +115,6 @@ public class CacheDataSource implements DataSource {
return result;
}
- @Override
- public int getIps(String ip) {
- return source.getIps(ip);
- }
-
- @Override
- public int purgeDatabase(long until) {
- int cleared = source.purgeDatabase(until);
- if (cleared > 0) {
- for (Optional auth : cachedAuths.asMap().values()) {
- if (auth.isPresent() && auth.get().getLastLogin() < until) {
- cachedAuths.invalidate(auth.get().getNickname());
- }
- }
- }
- return cleared;
- }
-
@Override
public List autoPurgeDatabase(long until) {
List cleared = source.autoPurgeDatabase(until);
@@ -172,11 +154,6 @@ public class CacheDataSource implements DataSource {
return result;
}
- @Override
- public synchronized List getAllAuthsByName(PlayerAuth auth) {
- return source.getAllAuthsByName(auth);
- }
-
@Override
public synchronized List getAllAuthsByIp(final String ip) {
return source.getAllAuthsByIp(ip);
@@ -239,6 +216,15 @@ public class CacheDataSource implements DataSource {
return result;
}
+ @Override
+ public boolean updateIp(String user, String ip) {
+ boolean result = source.updateIp(user, ip);
+ if (result) {
+ cachedAuths.refresh(user);
+ }
+ return result;
+ }
+
@Override
public List getAllAuths() {
return source.getAllAuths();
diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java
index ab46051c..43693313 100644
--- a/src/main/java/fr/xephi/authme/datasource/DataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java
@@ -6,146 +6,132 @@ import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.List;
/**
+ * Interface for manipulating {@link PlayerAuth} objects from a data source.
*/
public interface DataSource {
/**
- * Method isAuthAvailable.
+ * Return whether there is a record for the given username.
*
- * @param user String
+ * @param user The username to look up
*
- * @return boolean
+ * @return True if there is a record, false otherwise
*/
boolean isAuthAvailable(String user);
/**
- * Method getPassword.
+ * Return the hashed password of the player.
*
- * @param user String
+ * @param user The user whose password should be retrieve
*
- * @return String
+ * @return The password hash of the player
*/
HashedPassword getPassword(String user);
/**
- * Method getAuth.
+ * Retrieve the entire PlayerAuth object associated with the username.
*
- * @param user String
+ * @param user The user to retrieve
*
- * @return PlayerAuth
+ * @return The PlayerAuth object for the given username
*/
PlayerAuth getAuth(String user);
/**
- * Method saveAuth.
+ * Save a new PlayerAuth object.
*
- * @param auth PlayerAuth
+ * @param auth The new PlayerAuth to persist
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean saveAuth(PlayerAuth auth);
/**
- * Method updateSession.
+ * Update the session of a record (IP, last login, real name).
*
- * @param auth PlayerAuth
+ * @param auth The PlayerAuth object to update in the database
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean updateSession(PlayerAuth auth);
/**
- * Method updatePassword.
+ * Update the password of the given PlayerAuth object.
*
- * @param auth PlayerAuth
+ * @param auth The PlayerAuth whose password should be updated
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean updatePassword(PlayerAuth auth);
+ /**
+ * Update the password of the given player.
+ *
+ * @param user The user whose password should be updated
+ * @param password The new password
+ *
+ * @return True upon success, false upon failure
+ */
boolean updatePassword(String user, HashedPassword password);
/**
- * Method purgeDatabase.
+ * Purge all records in the database whose last login was longer ago than
+ * the given time.
*
- * @param until long
+ * @param until The minimum last login
*
- * @return int
- */
- int purgeDatabase(long until);
-
- /**
- * Method autoPurgeDatabase.
- *
- * @param until long
- *
- * @return List of String
+ * @return The account names that have been removed
*/
List autoPurgeDatabase(long until);
/**
- * Method removeAuth.
+ * Remove a user record from the database.
*
- * @param user String
+ * @param user The user to remove
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean removeAuth(String user);
/**
- * Method updateQuitLoc.
+ * Update the quit location of a PlayerAuth.
*
- * @param auth PlayerAuth
+ * @param auth The entry whose quit location should be updated
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean updateQuitLoc(PlayerAuth auth);
/**
- * Method getIps.
+ * Return all usernames associated with the given IP address.
*
- * @param ip String
+ * @param ip The IP address to look up
*
- * @return int
- */
- int getIps(String ip);
-
- /**
- * Method getAllAuthsByName.
- *
- * @param auth PlayerAuth
- *
- * @return List of String
- */
- List getAllAuthsByName(PlayerAuth auth);
-
- /**
- * Method getAllAuthsByIp.
- *
- * @param ip String
- *
- * @return List of String * @throws Exception
+ * @return Usernames associated with the given IP address
*/
List getAllAuthsByIp(String ip);
/**
- * Method getAllAuthsByEmail.
+ * Return all usernames associated with the given email address.
*
- * @param email String
+ * @param email The email address to look up
*
- * @return List of String * @throws Exception
+ * @return Users using the given email address
*/
List getAllAuthsByEmail(String email);
/**
- * Method updateEmail.
+ * Update the email of the PlayerAuth in the data source.
*
- * @param auth PlayerAuth
+ * @param auth The PlayerAuth whose email should be updated
*
- * @return boolean
+ * @return True upon success, false upon failure
*/
boolean updateEmail(PlayerAuth auth);
+ /**
+ * Close the underlying connections to the data source.
+ */
void close();
void reload();
@@ -205,6 +191,9 @@ public interface DataSource {
void updateName(String oldOne, String newOne);
boolean updateRealName(String user, String realName);
+
+ boolean updateIp(String user, String ip);
+
/**
* Method getAllAuths.
*
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index 6404e1c0..9bab76e1 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -278,82 +278,6 @@ public class FlatFile implements DataSource {
return true;
}
- @Override
- public int getIps(String ip) {
- BufferedReader br = null;
- int countIp = 0;
- try {
- br = new BufferedReader(new FileReader(source));
- String line;
- while ((line = br.readLine()) != null) {
- String[] args = line.split(":");
- if (args.length > 3 && args[2].equals(ip)) {
- countIp++;
- }
- }
- return countIp;
- } catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return 0;
- } catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return 0;
- } finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
- }
- }
-
- @Override
- public int purgeDatabase(long until) {
- BufferedReader br = null;
- BufferedWriter bw = null;
- ArrayList lines = new ArrayList<>();
- int cleared = 0;
- try {
- br = new BufferedReader(new FileReader(source));
- String line;
- while ((line = br.readLine()) != null) {
- String[] args = line.split(":");
- if (args.length >= 4) {
- if (Long.parseLong(args[3]) >= until) {
- lines.add(line);
- continue;
- }
- }
- cleared++;
- }
- bw = new BufferedWriter(new FileWriter(source));
- for (String l : lines) {
- bw.write(l + "\n");
- }
- } catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return cleared;
- } catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return cleared;
- } finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
- if (bw != null) {
- try {
- bw.close();
- } catch (IOException ignored) {
- }
- }
- }
- return cleared;
- }
-
@Override
public List autoPurgeDatabase(long until) {
BufferedReader br = null;
@@ -532,36 +456,6 @@ public class FlatFile implements DataSource {
return true;
}
- @Override
- public List getAllAuthsByName(PlayerAuth auth) {
- BufferedReader br = null;
- List countIp = new ArrayList<>();
- try {
- br = new BufferedReader(new FileReader(source));
- String line;
- while ((line = br.readLine()) != null) {
- String[] args = line.split(":");
- if (args.length > 3 && args[2].equals(auth.getIp())) {
- countIp.add(args[0]);
- }
- }
- return countIp;
- } catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return new ArrayList<>();
- } catch (IOException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return new ArrayList<>();
- } finally {
- if (br != null) {
- try {
- br.close();
- } catch (IOException ignored) {
- }
- }
- }
- }
-
@Override
public List getAllAuthsByIp(String ip) {
BufferedReader br = null;
@@ -721,6 +615,11 @@ public class FlatFile implements DataSource {
return false;
}
+ @Override
+ public boolean updateIp(String user, String ip) {
+ throw new UnsupportedOperationException("Flat file no longer supported");
+ }
+
@Override
public List getAllAuths() {
BufferedReader br = null;
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index 33fd0edd..a429d181 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -562,16 +562,14 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean updateSession(PlayerAuth auth) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET "
- + col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET "
+ + col.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.setTimestamp(2, new Timestamp(auth.getLastLogin()));
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getNickname());
pst.executeUpdate();
- pst.close();
return true;
} catch (SQLException ex) {
logSqlException(ex);
@@ -579,20 +577,6 @@ public class MySQL implements DataSource {
return false;
}
- @Override
- public synchronized int purgeDatabase(long until) {
- int result = 0;
- try (Connection con = getConnection()) {
- String sql = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- PreparedStatement pst = con.prepareStatement(sql);
- pst.setLong(1, until);
- result = pst.executeUpdate();
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return result;
- }
-
@Override
public synchronized List autoPurgeDatabase(long until) {
List list = new ArrayList<>();
@@ -669,25 +653,6 @@ public class MySQL implements DataSource {
return false;
}
- @Override
- public synchronized int getIps(String ip) {
- int countIp = 0;
- try (Connection con = getConnection()) {
- String sql = "SELECT COUNT(*) FROM " + tableName + " WHERE " + col.IP + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
- pst.setString(1, ip);
- ResultSet rs = pst.executeQuery();
- while (rs.next()) {
- countIp = rs.getInt(1);
- }
- rs.close();
- pst.close();
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return countIp;
- }
-
@Override
public synchronized boolean updateEmail(PlayerAuth auth) {
try (Connection con = getConnection()) {
@@ -722,25 +687,6 @@ public class MySQL implements DataSource {
}
}
- @Override
- public synchronized List getAllAuthsByName(PlayerAuth auth) {
- List result = new ArrayList<>();
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
- pst.setString(1, auth.getIp());
- ResultSet rs = pst.executeQuery();
- while (rs.next()) {
- result.add(rs.getString(col.NAME));
- }
- rs.close();
- pst.close();
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return result;
- }
-
@Override
public synchronized List getAllAuthsByIp(String ip) {
List result = new ArrayList<>();
@@ -900,6 +846,21 @@ public class MySQL implements DataSource {
return false;
}
+ @Override
+ public boolean updateIp(String user, String ip) {
+ try (Connection con = getConnection()) {
+ String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
+ PreparedStatement pst = con.prepareStatement(sql);
+ pst.setString(1, ip);
+ pst.setString(2, user);
+ pst.executeUpdate();
+ return true;
+ } catch (SQLException ex) {
+ logSqlException(ex);
+ }
+ return false;
+ }
+
@Override
public List getAllAuths() {
List auths = new ArrayList<>();
diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java
index 033bb838..081e386c 100644
--- a/src/main/java/fr/xephi/authme/datasource/SQLite.java
+++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java
@@ -266,18 +266,6 @@ public class SQLite implements DataSource {
return false;
}
- @Override
- public int purgeDatabase(long until) {
- String sql = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- try (PreparedStatement pst = con.prepareStatement(sql)) {
- pst.setLong(1, until);
- return pst.executeUpdate();
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- return 0;
- }
-
@Override
public List autoPurgeDatabase(long until) {
PreparedStatement pst = null;
@@ -336,29 +324,6 @@ public class SQLite implements DataSource {
return false;
}
- @Override
- public int getIps(String ip) {
- PreparedStatement pst = null;
- ResultSet rs = null;
- int countIp = 0;
- try {
- // TODO ljacqu 20151230: Simply fetch COUNT(1) and return that
- pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + col.IP + "=?;");
- pst.setString(1, ip);
- rs = pst.executeQuery();
- while (rs.next()) {
- countIp++;
- }
- return countIp;
- } catch (SQLException ex) {
- logSqlException(ex);
- } finally {
- close(rs);
- close(pst);
- }
- return 0;
- }
-
@Override
public boolean updateEmail(PlayerAuth auth) {
String sql = "UPDATE " + tableName + " SET " + col.EMAIL + "=? WHERE " + col.NAME + "=?;";
@@ -406,37 +371,13 @@ public class SQLite implements DataSource {
}
}
- @Override
- public List getAllAuthsByName(PlayerAuth auth) {
- PreparedStatement pst = null;
- ResultSet rs = null;
- List names = new ArrayList<>();
- try {
- // TODO ljacqu 20160214: Use SELECT name if only the name is required
- pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + col.IP + "=?;");
- pst.setString(1, auth.getIp());
- rs = pst.executeQuery();
- while (rs.next()) {
- names.add(rs.getString(col.NAME));
- }
- return names;
- } catch (SQLException ex) {
- logSqlException(ex);
-
- } finally {
- close(rs);
- close(pst);
- }
- return new ArrayList<>();
- }
-
@Override
public List getAllAuthsByIp(String ip) {
PreparedStatement pst = null;
ResultSet rs = null;
List countIp = new ArrayList<>();
try {
- pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + col.IP + "=?;");
+ pst = con.prepareStatement("SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;");
pst.setString(1, ip);
rs = pst.executeQuery();
while (rs.next()) {
@@ -607,6 +548,20 @@ public class SQLite implements DataSource {
return false;
}
+ @Override
+ public boolean updateIp(String user, String ip) {
+ String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
+ try(PreparedStatement pst = con.prepareStatement(sql)) {
+ pst.setString(1, ip);
+ pst.setString(2, user);
+ pst.executeUpdate();
+ return true;
+ } catch (SQLException ex) {
+ logSqlException(ex);
+ }
+ return false;
+ }
+
@Override
public List getAllAuths() {
List auths = new ArrayList<>();
diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
index c7673f70..d5908820 100644
--- a/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
+++ b/src/main/java/fr/xephi/authme/process/email/AsyncAddEmail.java
@@ -1,6 +1,7 @@
package fr.xephi.authme.process.email;
import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
@@ -48,8 +49,13 @@ public class AsyncAddEmail {
messages.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else {
auth.setEmail(email);
- playerCache.updatePlayer(auth);
- messages.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
+ if (dataSource.updateEmail(auth)) {
+ playerCache.updatePlayer(auth);
+ messages.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
+ } else {
+ ConsoleLogger.showError("Could not save email for player '" + player + "'");
+ messages.send(player, MessageKey.ERROR);
+ }
}
} else {
sendUnloggedMessage(dataSource);
diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
index 19b75f34..5a4cf425 100644
--- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
@@ -7,12 +7,12 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
+import fr.xephi.authme.output.MessageKey;
+import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.security.RandomString;
-import fr.xephi.authme.output.MessageKey;
-import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
@@ -23,7 +23,6 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
-import java.util.Date;
import java.util.List;
/**
@@ -143,7 +142,7 @@ public class AsynchronousLogin {
if (pAuth.getIp().equals("127.0.0.1") && !pAuth.getIp().equals(ip)) {
pAuth.setIp(ip);
- database.saveAuth(pAuth);
+ database.updateIp(pAuth.getNickname(), ip);
}
String email = pAuth.getEmail();
@@ -226,7 +225,7 @@ public class AsynchronousLogin {
return;
}
- List auths = this.database.getAllAuthsByName(auth);
+ List auths = this.database.getAllAuthsByIp(auth.getIp());
if (auths.size() < 2) {
return;
}
diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
index 29616fe5..ac921510 100644
--- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
@@ -1,19 +1,18 @@
package fr.xephi.authme.process.register;
import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.security.crypts.TwoFactor;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -21,11 +20,11 @@ import org.bukkit.entity.Player;
*/
public class AsyncRegister {
- protected final Player player;
- protected final String name;
- protected final String password;
+ private final Player player;
+ private final String name;
+ private final String password;
private final String ip;
- private String email = "";
+ private final String email;
private final AuthMe plugin;
private final DataSource database;
private final Messages m;
@@ -88,7 +87,7 @@ public class AsyncRegister {
public void process() {
if (preRegisterCheck()) {
- if (email != null && !email.isEmpty()) {
+ if (!StringUtils.isEmpty(email)) {
emailRegister();
} else {
passwordRegister();
diff --git a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java
index 065d1961..f878d85a 100644
--- a/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java
+++ b/src/main/java/fr/xephi/authme/util/GeoLiteAPI.java
@@ -1,6 +1,6 @@
package fr.xephi.authme.util;
-import com.maxmind.geoip2.DatabaseReader;
+import com.maxmind.geoip.LookupService;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.Settings;
@@ -9,18 +9,17 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
public class GeoLiteAPI {
-
- private static final String LICENSE = "[LICENSE] This product includes GeoLite2 data created by MaxMind," +
- " available from http://www.maxmind.com";
- private static final String GEOIP_URL = "http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz";
- private static DatabaseReader databaseReader;
+ private static final String LICENSE =
+ "[LICENSE] This product uses data from the GeoLite API created by MaxMind, available at http://www.maxmind.com";
+ private static final String GEOIP_URL =
+ "http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz";
+ private static LookupService lookupService;
private static Thread downloadTask;
/**
@@ -32,17 +31,17 @@ public class GeoLiteAPI {
if (downloadTask != null && downloadTask.isAlive()) {
return false;
}
- if (databaseReader != null) {
+ if (lookupService != null) {
return true;
}
- final File data = new File(Settings.PLUGIN_FOLDER, "GeoLite2-Country.mmdb");
+ final File data = new File(Settings.PLUGIN_FOLDER, "GeoIP.dat");
boolean dataIsOld = (System.currentTimeMillis() - data.lastModified()) > TimeUnit.DAYS.toMillis(30);
if (dataIsOld && !data.delete()) {
ConsoleLogger.showError("Failed to delete GeoLiteAPI database");
}
if (data.exists()) {
try {
- databaseReader = new DatabaseReader.Builder(data).build();
+ lookupService = new LookupService(data);
ConsoleLogger.info(LICENSE);
return true;
} catch (IOException e) {
@@ -90,11 +89,7 @@ public class GeoLiteAPI {
*/
public static String getCountryCode(String ip) {
if (!"127.0.0.1".equals(ip) && isDataAvailable()) {
- try {
- return databaseReader.country(InetAddress.getByName(ip)).getCountry().getIsoCode();
- } catch (Exception e) {
- ConsoleLogger.writeStackTrace(e);
- }
+ return lookupService.getCountry(ip).getCode();
}
return "--";
}
@@ -108,11 +103,7 @@ public class GeoLiteAPI {
*/
public static String getCountryName(String ip) {
if (!"127.0.0.1".equals(ip) && isDataAvailable()) {
- try {
- return databaseReader.country(InetAddress.getByName(ip)).getCountry().getName();
- } catch (Exception e) {
- ConsoleLogger.writeStackTrace(e);
- }
+ return lookupService.getCountry(ip).getName();
}
return "N/A";
}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index be7b792f..bf63b364 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -16,7 +16,7 @@ softdepend:
commands:
authme:
description: AuthMe op commands
- usage: '/authme reload|register playername password|changepassword playername password|unregister playername|version'
+ usage: '/authme reload|register playername password|changepassword playername password|unregister playername|version|converter'
register:
description: Register an account
usage: /register
@@ -40,9 +40,6 @@ commands:
captcha:
description: Captcha command
usage: /captcha
- converter:
- description: Converter from different other auth plugins
- usage: /converter
permissions:
authme.admin.*:
description: Give access to all admin commands.
diff --git a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
index f8b0d256..62c2b890 100644
--- a/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandInitializerTest.java
@@ -50,7 +50,7 @@ public class CommandInitializerTest {
// It obviously doesn't make sense to test much of the concrete data
// that is being initialized; we just want to guarantee with this test
// that data is indeed being initialized and we take a few "probes"
- assertThat(commands.size(), equalTo(9));
+ assertThat(commands.size(), equalTo(8));
assertThat(commandsIncludeLabel(commands, "authme"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "register"), equalTo(true));
assertThat(commandsIncludeLabel(commands, "help"), equalTo(false));
diff --git a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java
index 4743f699..92bcf4fc 100644
--- a/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java
+++ b/src/test/java/fr/xephi/authme/command/executable/authme/AccountsCommandTest.java
@@ -16,7 +16,6 @@ import java.util.List;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -48,8 +47,8 @@ public class AccountsCommandTest {
// given
given(sender.getName()).willReturn("Tester");
List arguments = Collections.EMPTY_LIST;
- given(dataSource.getAuth("tester")).willReturn(mock(PlayerAuth.class));
- given(dataSource.getAllAuthsByName(any(PlayerAuth.class))).willReturn(Arrays.asList("Toaster", "Pester"));
+ given(dataSource.getAuth("tester")).willReturn(authWithIp("123.45.67.89"));
+ given(dataSource.getAllAuthsByIp("123.45.67.89")).willReturn(Arrays.asList("Toaster", "Pester"));
// when
command.executeCommand(sender, arguments, service);
@@ -81,7 +80,7 @@ public class AccountsCommandTest {
// given
List arguments = Collections.singletonList("SomeUser");
given(dataSource.getAuth("someuser")).willReturn(mock(PlayerAuth.class));
- given(dataSource.getAllAuthsByName(any(PlayerAuth.class))).willReturn(Collections.EMPTY_LIST);
+ given(dataSource.getAllAuthsByIp(anyString())).willReturn(Collections.EMPTY_LIST);
// when
command.executeCommand(sender, arguments, service);
@@ -96,8 +95,8 @@ public class AccountsCommandTest {
public void shouldReturnSingleAccountMessage() {
// given
List arguments = Collections.singletonList("SomeUser");
- given(dataSource.getAuth("someuser")).willReturn(mock(PlayerAuth.class));
- given(dataSource.getAllAuthsByName(any(PlayerAuth.class))).willReturn(Collections.singletonList("SomeUser"));
+ given(dataSource.getAuth("someuser")).willReturn(authWithIp("56.78.90.123"));
+ given(dataSource.getAllAuthsByIp("56.78.90.123")).willReturn(Collections.singletonList("SomeUser"));
// when
command.executeCommand(sender, arguments, service);
@@ -169,4 +168,11 @@ public class AccountsCommandTest {
verify(sender, times(expectedCount)).sendMessage(captor.capture());
return captor.getAllValues().toArray(new String[expectedCount]);
}
+
+ private static PlayerAuth authWithIp(String ip) {
+ return PlayerAuth.builder()
+ .name("Test")
+ .ip(ip)
+ .build();
+ }
}
diff --git a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
index 4aea5e57..7cc7c55d 100644
--- a/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
+++ b/src/test/java/fr/xephi/authme/process/email/AsyncAddEmailTest.java
@@ -1,6 +1,7 @@
package fr.xephi.authme.process.email;
import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
@@ -35,6 +36,7 @@ public class AsyncAddEmailTest {
@BeforeClass
public static void setUp() {
WrapperMock.createInstance();
+ ConsoleLoggerTestInitializer.setupLogger();
}
// Clean up the fields to ensure that no test uses elements of another test
@@ -56,16 +58,38 @@ public class AsyncAddEmailTest {
given(auth.getEmail()).willReturn(null);
given(playerCache.getAuth("tester")).willReturn(auth);
given(dataSource.isEmailStored("my.mail@example.org")).willReturn(false);
+ given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(true);
// when
process.process();
// then
+ verify(dataSource).updateEmail(auth);
verify(messages).send(player, MessageKey.EMAIL_ADDED_SUCCESS);
verify(auth).setEmail("my.mail@example.org");
verify(playerCache).updatePlayer(auth);
}
+ @Test
+ public void shouldReturnErrorWhenMailCannotBeSaved() {
+ // given
+ AsyncAddEmail process = createProcess("my.mail@example.org");
+ given(player.getName()).willReturn("testEr");
+ given(playerCache.isAuthenticated("tester")).willReturn(true);
+ PlayerAuth auth = mock(PlayerAuth.class);
+ given(auth.getEmail()).willReturn(null);
+ given(playerCache.getAuth("tester")).willReturn(auth);
+ given(dataSource.isEmailStored("my.mail@example.org")).willReturn(false);
+ given(dataSource.updateEmail(any(PlayerAuth.class))).willReturn(false);
+
+ // when
+ process.process();
+
+ // then
+ verify(dataSource).updateEmail(auth);
+ verify(messages).send(player, MessageKey.ERROR);
+ }
+
@Test
public void shouldNotAddMailIfPlayerAlreadyHasEmail() {
// given
diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java
index 64a79626..d381604c 100644
--- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java
+++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java
@@ -5,8 +5,7 @@ import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
import java.io.File;
@@ -32,10 +31,10 @@ public class NewSettingTest {
public void shouldLoadAllConfigs() {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
- given(configuration.getString(anyString(), anyString())).willAnswer(withDefaultArgument());
- given(configuration.getBoolean(anyString(), anyBoolean())).willAnswer(withDefaultArgument());
- given(configuration.getDouble(anyString(), anyDouble())).willAnswer(withDefaultArgument());
- given(configuration.getInt(anyString(), anyInt())).willAnswer(withDefaultArgument());
+ given(configuration.getString(anyString(), anyString())).willAnswer(new ReturnsArgumentAt(1));
+ given(configuration.getBoolean(anyString(), anyBoolean())).willAnswer(new ReturnsArgumentAt(1));
+ given(configuration.getDouble(anyString(), anyDouble())).willAnswer(new ReturnsArgumentAt(1));
+ given(configuration.getInt(anyString(), anyInt())).willAnswer(new ReturnsArgumentAt(1));
setReturnValue(configuration, TestConfiguration.VERSION_NUMBER, 20);
setReturnValue(configuration, TestConfiguration.SKIP_BORING_FEATURES, true);
@@ -89,14 +88,4 @@ public class NewSettingTest {
setting.getProperty(property).equals(property.getDefaultValue()), equalTo(true));
}
- private static Answer withDefaultArgument() {
- return new Answer() {
- @Override
- public T answer(InvocationOnMock invocation) throws Throwable {
- // Return the second parameter -> the default
- return (T) invocation.getArguments()[1];
- }
- };
- }
-
}