Add support for postgresql

This commit is contained in:
2024-04-04 17:43:23 +02:00
parent a65a5f3020
commit 56e43fb146
5 changed files with 167 additions and 13 deletions

View File

@ -117,10 +117,10 @@ Install the plugin on both platforms, that is proxy (BungeeCord or Velocity) and
4. Activate ip forwarding in your proxy config
5. Check your database settings in the config of FastLogin on your proxy
* The proxies only ship with a limited set of drivers where Spigot supports more. Therefore, these are supported:
* BungeeCord: `com.mysql.jdbc.Driver` for MySQL/MariaDB
* Velocity: `fastlogin.mariadb.jdbc.Driver` for MySQL/MariaDB
* BungeeCord: `com.mysql.jdbc.Driver` for MySQL/MariaDB/PostgreSQL
* Velocity: `fastlogin.mariadb.jdbc.Driver` for MySQL/MariaDB/PostgreSQL
* Note the embedded file storage SQLite is not available
* MySQL/MariaDB requires an external database server running. Check your server provider if there is one available
* MySQL/MariaDB/PostgreSQL requires an external database server running. Check your server provider if there is one available
or install one.
6. Set proxy and Spigot in offline mode by setting the value `onlinemode` in your `config.yml` to false
7. You should *always* configure the firewall for your Spigot server so that it's only accessible through your proxy

View File

@ -36,6 +36,7 @@ import com.github.games647.fastlogin.core.antibot.TickingRateLimiter;
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
import com.github.games647.fastlogin.core.storage.PostgreSQLStorage;
import com.github.games647.fastlogin.core.storage.MySQLStorage;
import com.github.games647.fastlogin.core.storage.SQLStorage;
import com.github.games647.fastlogin.core.storage.SQLiteStorage;
@ -230,6 +231,24 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
if (type.contains("sqlite")) {
storage = new SQLiteStorage(plugin, database, databaseConfig);
} else if (type.contains("postgresql")) {
String host = config.get("host", "");
int port = config.get("port", 3306);
boolean useSSL = config.get("useSSL", false);
if (useSSL) {
boolean publicKeyRetrieval = config.getBoolean("allowPublicKeyRetrieval", false);
String rsaPublicKeyFile = config.getString("ServerRSAPublicKeyFile");
String sslMode = config.getString("sslMode", "Required");
databaseConfig.addDataSourceProperty("allowPublicKeyRetrieval", publicKeyRetrieval);
databaseConfig.addDataSourceProperty("serverRSAPublicKeyFile", rsaPublicKeyFile);
databaseConfig.addDataSourceProperty("sslMode", sslMode);
}
databaseConfig.setUsername(config.get("username", ""));
databaseConfig.setPassword(config.getString("password"));
storage = new PostgreSQLStorage(plugin, type, host, port, database, databaseConfig, useSSL);
} else {
String host = config.get("host", "");
int port = config.get("port", 3306);

View File

@ -0,0 +1,101 @@
/*
* SPDX-License-Identifier: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 games647 and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.github.games647.fastlogin.core.storage;
import com.github.games647.fastlogin.core.shared.PlatformPlugin;
import com.zaxxer.hikari.HikariConfig;
public class PostgreSQLStorage extends SQLStorage {
private static final String JDBC_PROTOCOL = "jdbc:";
public PostgreSQLStorage(PlatformPlugin<?> plugin, String driver, String host, int port, String database,
HikariConfig config, boolean useSSL) {
super(plugin.getLog(), plugin.getName(), plugin.getThreadFactory(),
setParams(config, driver, host, port, database, useSSL));
}
private static HikariConfig setParams(HikariConfig config,
String driver, String host, int port, String database,
boolean useSSL) {
// Require SSL on the server if requested in config - this will also verify certificate
// Those values are deprecated in favor of sslMode
config.addDataSourceProperty("useSSL", useSSL);
config.addDataSourceProperty("requireSSL", useSSL);
// adding paranoid, hides hostname, username, version and so
// could be useful for hiding server details
config.addDataSourceProperty("paranoid", true);
config.setJdbcUrl(JDBC_PROTOCOL + buildJDBCUrl(driver, host, port, database));
return config;
}
private static String buildJDBCUrl(String driver, String host, int port, String database) {
return "postgresql://" + host + ':' + port + '/' + database;
}
@Override
protected String getCreateTableStmt() {
// PostgreSQL has a different syntax for id column
return CREATE_TABLE_STMT
.replace("`", "\"")
.replace("INTEGER PRIMARY KEY AUTO_INCREMENT", "SERIAL PRIMARY KEY");
}
@Override
protected String getAddFloodgateColumnStmt() {
// PostgreSQL has a different syntax
return ADD_FLOODGATE_COLUMN_STMT
.replace("`", "\"")
.replace("INTEGER(3)", "INTEGER");
}
@Override
protected String getLoadByNameStmt() {
return LOAD_BY_NAME_STMT
.replace("`", "\"");
}
@Override
protected String getLoadByUuidStmt() {
return LOAD_BY_UUID_STMT
.replace("`", "\"");
}
@Override
protected String getInsertProfileStmt() {
return INSERT_PROFILE_STMT
.replace("`", "\"");
}
@Override
protected String getUpdateProfileStmt() {
return UPDATE_PROFILE_STMT
.replace("`", "\"");
}
}

View File

@ -61,14 +61,14 @@ public abstract class SQLStorage implements AuthStorage {
protected static final String ADD_FLOODGATE_COLUMN_STMT = "ALTER TABLE `" + PREMIUM_TABLE
+ "` ADD COLUMN `Floodgate` INTEGER(3)";
protected static final String LOAD_BY_NAME = "SELECT * FROM `" + PREMIUM_TABLE
protected static final String LOAD_BY_NAME_STMT = "SELECT * FROM `" + PREMIUM_TABLE
+ "` WHERE `Name`=? LIMIT 1";
protected static final String LOAD_BY_UUID = "SELECT * FROM `" + PREMIUM_TABLE
protected static final String LOAD_BY_UUID_STMT = "SELECT * FROM `" + PREMIUM_TABLE
+ "` WHERE `UUID`=? LIMIT 1";
protected static final String INSERT_PROFILE = "INSERT INTO `" + PREMIUM_TABLE
protected static final String INSERT_PROFILE_STMT = "INSERT INTO `" + PREMIUM_TABLE
+ "` (`UUID`, `Name`, `Premium`, `Floodgate`, `LastIp`) " + "VALUES (?, ?, ?, ?, ?) ";
// limit not necessary here, because it's unique
protected static final String UPDATE_PROFILE = "UPDATE `" + PREMIUM_TABLE
protected static final String UPDATE_PROFILE_STMT = "UPDATE `" + PREMIUM_TABLE
+ "` SET `UUID`=?, `Name`=?, `Premium`=?, `Floodgate`=?, `LastIp`=?, "
+ "`LastLogin`=CURRENT_TIMESTAMP WHERE `UserID`=?";
@ -97,7 +97,7 @@ public abstract class SQLStorage implements AuthStorage {
// add Floodgate column
DatabaseMetaData md = con.getMetaData();
if (isColumnMissing(md, "Floodgate")) {
stmt.executeUpdate(ADD_FLOODGATE_COLUMN_STMT);
stmt.executeUpdate(getAddFloodgateColumnStmt());
}
}
@ -112,7 +112,7 @@ public abstract class SQLStorage implements AuthStorage {
@Override
public StoredProfile loadProfile(String name) {
try (Connection con = dataSource.getConnection();
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_NAME)
PreparedStatement loadStmt = con.prepareStatement(getLoadByNameStmt())
) {
loadStmt.setString(1, name);
@ -130,7 +130,7 @@ public abstract class SQLStorage implements AuthStorage {
@Override
public StoredProfile loadProfile(UUID uuid) {
try (Connection con = dataSource.getConnection();
PreparedStatement loadStmt = con.prepareStatement(LOAD_BY_UUID)) {
PreparedStatement loadStmt = con.prepareStatement(getLoadByUuidStmt())) {
loadStmt.setString(1, UUIDAdapter.toMojangId(uuid));
try (ResultSet resultSet = loadStmt.executeQuery()) {
@ -177,7 +177,7 @@ public abstract class SQLStorage implements AuthStorage {
playerProfile.getSaveLock().lock();
try {
if (playerProfile.isSaved()) {
try (PreparedStatement saveStmt = con.prepareStatement(UPDATE_PROFILE)) {
try (PreparedStatement saveStmt = con.prepareStatement(getUpdateProfileStmt())) {
saveStmt.setString(1, uuid);
saveStmt.setString(2, playerProfile.getName());
saveStmt.setBoolean(3, playerProfile.isPremium());
@ -188,7 +188,8 @@ public abstract class SQLStorage implements AuthStorage {
saveStmt.execute();
}
} else {
try (PreparedStatement saveStmt = con.prepareStatement(INSERT_PROFILE, RETURN_GENERATED_KEYS)) {
try (PreparedStatement saveStmt = con.prepareStatement(getInsertProfileStmt(),
RETURN_GENERATED_KEYS)) {
saveStmt.setString(1, uuid);
saveStmt.setString(2, playerProfile.getName());
@ -214,13 +215,37 @@ public abstract class SQLStorage implements AuthStorage {
}
/**
* SQLite has a slightly different syntax, so this will be overridden by SQLiteStorage
* SQLite and PostgreSQL have a slightly different syntax, so this will be overridden by SQLiteStorage and so on...
* @return An SQL Statement to create the `premium` table
*/
protected String getCreateTableStmt() {
return CREATE_TABLE_STMT;
}
/**
* PostgreSQL has a slightly different syntax, so this will be overridden by PostgreSQLStorage
* @return An SQL Statement to create the `premium` table
*/
protected String getAddFloodgateColumnStmt() {
return ADD_FLOODGATE_COLUMN_STMT;
}
protected String getLoadByNameStmt() {
return LOAD_BY_NAME_STMT;
}
protected String getLoadByUuidStmt() {
return LOAD_BY_UUID_STMT;
}
protected String getInsertProfileStmt() {
return INSERT_PROFILE_STMT;
}
protected String getUpdateProfileStmt() {
return UPDATE_PROFILE_STMT;
}
@Override
public void close() {
dataSource.close();

View File

@ -289,6 +289,15 @@ database: '{pluginDir}/FastLogin.db'
#username: 'myUser'
#password: 'myPassword'
# PostgreSQL
# If you want to enable it, uncomment only the lines below; this not this line.
#driver: 'postgresql'
#host: '127.0.0.1'
#port: 5432
#database: 'fastlogin'
#username: 'myUser'
#password: 'myPassword'
# Advanced Connection Pool settings in seconds
#timeout: 30
#lifetime: 30