mirror of
https://github.com/funkemunky/AntiVPN.git
synced 2026-05-31 01:21:55 +00:00
Adding postgres
This commit is contained in:
@@ -23,6 +23,7 @@ import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.mongo.MongoVPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.loader.LoaderBootstrap;
|
||||
import lombok.Getter;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
@@ -151,6 +152,8 @@ public class BukkitPlugin implements LoaderBootstrap {
|
||||
|
||||
if(database instanceof MySqlVPN) {
|
||||
return "MySQL";
|
||||
} else if(database instanceof PostgreSqlVPN) {
|
||||
return "PostgreSQL";
|
||||
} else if(database instanceof H2VPN) {
|
||||
return "H2";
|
||||
} else if(database instanceof MongoVPN) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.mongo.MongoVPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.loader.LoaderBootstrap;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
@@ -87,6 +88,8 @@ public class BungeePlugin implements LoaderBootstrap {
|
||||
VPNDatabase database = AntiVPN.getInstance().getDatabase();
|
||||
if(database instanceof MySqlVPN) {
|
||||
return "MySQL";
|
||||
} else if(database instanceof PostgreSqlVPN) {
|
||||
return "PostgreSQL";
|
||||
} else if(database instanceof H2VPN) {
|
||||
return "H2";
|
||||
} else if(database instanceof MongoVPN) {
|
||||
|
||||
@@ -9,6 +9,7 @@ dependencies {
|
||||
implementation 'org.jetbrains:annotations:26.0.2'
|
||||
|
||||
compileOnly 'com.mysql:mysql-connector-j:9.3.0'
|
||||
compileOnly 'org.postgresql:postgresql:42.7.3'
|
||||
compileOnly 'com.h2database:h2:2.2.220'
|
||||
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.1.8'
|
||||
compileOnly 'org.mongodb:mongo-java-driver:3.12.14'
|
||||
@@ -18,9 +19,11 @@ dependencies {
|
||||
testImplementation "org.testcontainers:testcontainers:2.0.4"
|
||||
testImplementation "org.testcontainers:testcontainers-junit-jupiter:2.0.4"
|
||||
testImplementation 'org.testcontainers:mysql:1.20.4'
|
||||
testImplementation 'org.testcontainers:postgresql:1.20.4'
|
||||
testImplementation 'org.testcontainers:mongodb:1.20.4'
|
||||
testRuntimeOnly 'org.slf4j:slf4j-simple:2.0.16'
|
||||
testImplementation 'com.mysql:mysql-connector-j:9.3.0'
|
||||
testImplementation 'org.postgresql:postgresql:42.7.3'
|
||||
testImplementation 'com.h2database:h2:2.2.220'
|
||||
testImplementation 'org.mongodb:mongo-java-driver:3.12.14'
|
||||
testImplementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
|
||||
@@ -35,6 +38,7 @@ shadowJar {
|
||||
relocate 'com.mongodb', 'dev.brighten.antivpn.shaded.com.mongodb'
|
||||
relocate 'com.mysql.cj', 'dev.brighten.antivpn.shaded.com.mysql.cj'
|
||||
relocate 'com.mysql.jdbc', 'dev.brighten.antivpn.shaded.com.mysql.jdbc'
|
||||
relocate 'org.postgresql', 'dev.brighten.antivpn.shaded.org.postgresql'
|
||||
|
||||
dependencies {
|
||||
exclude 'dev/brighten/antivpn/depends/Relocate*'
|
||||
|
||||
@@ -25,6 +25,7 @@ import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.mongo.MongoVPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.depends.LibraryLoader;
|
||||
import dev.brighten.antivpn.depends.MavenLibrary;
|
||||
import dev.brighten.antivpn.depends.Relocate;
|
||||
@@ -45,6 +46,7 @@ import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
@Setter(AccessLevel.PRIVATE)
|
||||
@@ -63,6 +65,14 @@ import java.util.List;
|
||||
@Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc"),
|
||||
}
|
||||
)
|
||||
@MavenLibrary(
|
||||
groupId = "org.postgresql",
|
||||
artifactId = "postgresql",
|
||||
version = "42.7.3",
|
||||
relocations = {
|
||||
@Relocate(from = "org\\.postgresql", to = "dev.brighten.antivpn.shaded.org.postgresql"),
|
||||
}
|
||||
)
|
||||
@MavenLibrary(groupId = "com.\\github\\.ben-manes\\.caffeine", artifactId = "caffeine", version = "3.1.8",
|
||||
relocations = {
|
||||
@Relocate(from = "com\\.github\\.benmanes\\.caffeine", to = "dev.brighten.antivpn.shaded.com.github.benmanes.caffeine"),
|
||||
@@ -115,35 +125,7 @@ public class AntiVPN {
|
||||
INSTANCE.messageHandler = new MessageHandler();
|
||||
|
||||
try {
|
||||
switch(INSTANCE.vpnConfig.getDatabaseType().toLowerCase()) {
|
||||
case "h2":
|
||||
case "local":
|
||||
case "flatfile": {
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType H2...");
|
||||
INSTANCE.database = new H2VPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mysql":
|
||||
case "sql": {
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL...");
|
||||
INSTANCE.database = new MySqlVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mongo":
|
||||
case "mongodb":
|
||||
case "mongod": {
|
||||
INSTANCE.database = new MongoVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " +
|
||||
"Options: [MySQL]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
INSTANCE.initializeDatabase();
|
||||
} catch (Exception e) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Could not initialize database, plugin disabling...", e);
|
||||
executor.disablePlugin();
|
||||
@@ -192,7 +174,7 @@ public class AntiVPN {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (database instanceof H2VPN) {
|
||||
if (database != null && database.getClass() == H2VPN.class) {
|
||||
database.shutdown();
|
||||
|
||||
// Try to deregister driver
|
||||
@@ -216,36 +198,7 @@ public class AntiVPN {
|
||||
|
||||
public void reloadDatabase() {
|
||||
database.shutdown();
|
||||
|
||||
switch(AntiVPN.getInstance().getVpnConfig().getDatabaseType().toLowerCase()) {
|
||||
case "h2":
|
||||
case "local":
|
||||
case "flatfile": {
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType H2...");
|
||||
INSTANCE.database = new H2VPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mysql":
|
||||
case "sql":{
|
||||
AntiVPN.getInstance().getExecutor().log("Using databaseType MySQL...");
|
||||
INSTANCE.database = new MySqlVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
case "mongo":
|
||||
case "mongodb":
|
||||
case "mongod": {
|
||||
INSTANCE.database = new MongoVPN();
|
||||
INSTANCE.database.init();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
AntiVPN.getInstance().getExecutor().log("Could not find database type \"" + INSTANCE.vpnConfig.getDatabaseType() + "\". " +
|
||||
"Options: [MySQL]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
initializeDatabase();
|
||||
}
|
||||
|
||||
public static AntiVPN getInstance() {
|
||||
@@ -276,4 +229,37 @@ public class AntiVPN {
|
||||
private void registerCommands() {
|
||||
commands.add(new AntiVPNCommand());
|
||||
}
|
||||
|
||||
private void initializeDatabase() {
|
||||
database = createConfiguredDatabase();
|
||||
database.init();
|
||||
}
|
||||
|
||||
private VPNDatabase createConfiguredDatabase() {
|
||||
String configuredType = vpnConfig.getDatabaseType();
|
||||
String databaseType = configuredType.toLowerCase(Locale.ROOT);
|
||||
|
||||
return switch (databaseType) {
|
||||
case "h2", "local", "flatfile" -> {
|
||||
getExecutor().log("Using databaseType H2...");
|
||||
yield new H2VPN();
|
||||
}
|
||||
case "mysql", "sql" -> {
|
||||
getExecutor().log("Using databaseType MySQL...");
|
||||
yield new MySqlVPN();
|
||||
}
|
||||
case "postgres", "postgresql", "psql" -> {
|
||||
getExecutor().log("Using databaseType PostgreSQL...");
|
||||
yield new PostgreSqlVPN();
|
||||
}
|
||||
case "mongo", "mongodb", "mongod" -> {
|
||||
getExecutor().log("Using databaseType MongoDB...");
|
||||
yield new MongoVPN();
|
||||
}
|
||||
default -> throw new IllegalArgumentException(
|
||||
"Could not find database type \"" + configuredType
|
||||
+ "\". Options: [H2, MySQL, PostgreSQL, MongoDB]"
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,10 @@ public class VPNConfig {
|
||||
case "mongo":
|
||||
case "mongod":
|
||||
return 27017;
|
||||
case "postgresql":
|
||||
case "postgres":
|
||||
case "psql":
|
||||
return 5432;
|
||||
case "sql":
|
||||
case "mysql":
|
||||
return 3306;
|
||||
@@ -222,4 +226,4 @@ public class VPNConfig {
|
||||
countryVanillaKickReason = defaultCountryKickReason.get();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,11 +88,11 @@ public class First implements Version<VPNDatabase> {
|
||||
return;
|
||||
}
|
||||
|
||||
closeOnEnd(Query.prepare(String.format(
|
||||
"drop index `%s` on `%s`",
|
||||
indexName,
|
||||
tableName
|
||||
))).execute();
|
||||
String sql = Query.getDialect().isPostgreSql()
|
||||
? String.format("drop index \"%s\"", indexName)
|
||||
: String.format("drop index `%s` on `%s`", indexName, tableName);
|
||||
|
||||
closeOnEnd(Query.prepare(sql)).execute();
|
||||
}
|
||||
|
||||
protected boolean hasIndex(String tableName, String indexName) throws SQLException {
|
||||
|
||||
@@ -21,6 +21,7 @@ import dev.brighten.antivpn.database.DatabaseException;
|
||||
import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.utils.ExecutableStatement;
|
||||
import dev.brighten.antivpn.database.sql.utils.Query;
|
||||
import dev.brighten.antivpn.database.version.Version;
|
||||
@@ -37,7 +38,9 @@ public class Second extends First implements Version<VPNDatabase> {
|
||||
|
||||
@Override
|
||||
public void update(VPNDatabase database) throws DatabaseException {
|
||||
if(database instanceof H2VPN h2VPN && !(database instanceof MySqlVPN)) {
|
||||
if(database instanceof H2VPN h2VPN
|
||||
&& !(database instanceof MySqlVPN)
|
||||
&& !(database instanceof PostgreSqlVPN)) {
|
||||
h2VPN.backupDatabase();
|
||||
}
|
||||
List<String> whitelistedIps = new ArrayList<>();
|
||||
|
||||
@@ -21,32 +21,14 @@ import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.sql.utils.MySQL;
|
||||
import dev.brighten.antivpn.database.version.Version;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MySqlVPN extends H2VPN {
|
||||
|
||||
public MySqlVPN() {
|
||||
AntiVPN.getInstance().getExecutor().getThreadExecutor().scheduleAtFixedRate(() -> {
|
||||
if(!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled() || MySQL.isClosed()) return;
|
||||
|
||||
//Refreshing whitelisted players
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelisted()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelisted());
|
||||
|
||||
//Refreshing whitlisted IPs
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps().clear();
|
||||
AntiVPN.getInstance().getExecutor().getWhitelistedIps()
|
||||
.addAll(AntiVPN.getInstance().getDatabase().getAllWhitelistedIps());
|
||||
}, 2, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled())
|
||||
return;
|
||||
AntiVPN.getInstance().getExecutor().log("Initializing MySQL...");
|
||||
MySQL.init();
|
||||
MySQL.initMySql();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Checking for updates...");
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2026 Dawson Hessler
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.database.sql;
|
||||
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.sql.utils.MySQL;
|
||||
import dev.brighten.antivpn.database.version.Version;
|
||||
|
||||
public class PostgreSqlVPN extends H2VPN {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (!AntiVPN.getInstance().getVpnConfig().isDatabaseEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Initializing PostgreSQL...");
|
||||
MySQL.initPostgreSql();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Checking for updates...");
|
||||
|
||||
try {
|
||||
for (Version<PostgreSqlVPN> version : Version.postgresVersions) {
|
||||
if (version.needsUpdate(this)) {
|
||||
version.update(this);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not complete version setup due to SQL error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,12 @@ import com.mysql.cj.jdbc.Driver;
|
||||
import dev.brighten.antivpn.AntiVPN;
|
||||
import org.h2.jdbc.JdbcSQLFeatureNotSupportedException;
|
||||
import org.h2.jdbc.JdbcSQLNonTransientConnectionException;
|
||||
import org.postgresql.util.PSQLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLSyntaxErrorException;
|
||||
@@ -34,6 +36,10 @@ public class MySQL {
|
||||
private static Connection conn;
|
||||
|
||||
public static void init() {
|
||||
initMySql();
|
||||
}
|
||||
|
||||
public static void initMySql() {
|
||||
try {
|
||||
if (conn == null || conn.isClosed()) {
|
||||
String url = "jdbc:mysql://" + AntiVPN.getInstance().getVpnConfig().getIp()
|
||||
@@ -72,12 +78,90 @@ public class MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
public static void initPostgreSql() {
|
||||
try {
|
||||
if (conn == null || conn.isClosed()) {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("user", AntiVPN.getInstance().getVpnConfig().getUsername());
|
||||
properties.setProperty("password", AntiVPN.getInstance().getVpnConfig().getPassword());
|
||||
|
||||
String host = AntiVPN.getInstance().getVpnConfig().getIp();
|
||||
int port = AntiVPN.getInstance().getVpnConfig().getPort();
|
||||
String databaseName = AntiVPN.getInstance().getVpnConfig().getDatabaseName();
|
||||
|
||||
String adminUrl = "jdbc:postgresql://" + host + ":" + port + "/postgres";
|
||||
try (Connection adminConnection = new org.postgresql.Driver().connect(adminUrl, properties)) {
|
||||
if (adminConnection == null) {
|
||||
throw new SQLException("PostgreSQL driver did not accept URL: " + adminUrl);
|
||||
}
|
||||
|
||||
adminConnection.setAutoCommit(true);
|
||||
ensurePostgreSqlDatabase(adminConnection, databaseName);
|
||||
}
|
||||
|
||||
String databaseUrl = "jdbc:postgresql://" + host + ":" + port + "/" + databaseName;
|
||||
conn = new org.postgresql.Driver().connect(databaseUrl, properties);
|
||||
if (conn == null) {
|
||||
throw new SQLException("PostgreSQL driver did not accept URL: " + databaseUrl);
|
||||
}
|
||||
|
||||
conn.setAutoCommit(true);
|
||||
Query.use(conn);
|
||||
AntiVPN.getInstance().getExecutor().log("Connection to PostgreSQL has been established.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Failed to load postgresql: " + e.getMessage(), e);
|
||||
throw new RuntimeException("Could not initialize PostgreSQL connection", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDatabaseCreationPermissionIssue(SQLException ex) {
|
||||
return ex instanceof SQLSyntaxErrorException
|
||||
&& ex.getMessage() != null
|
||||
&& ex.getMessage().contains("Access denied");
|
||||
}
|
||||
|
||||
private static void ensurePostgreSqlDatabase(Connection adminConnection, String databaseName) throws SQLException {
|
||||
try (var statement = adminConnection.prepareStatement("SELECT 1 FROM pg_database WHERE datname = ?")) {
|
||||
statement.setString(1, databaseName);
|
||||
|
||||
try (var resultSet = statement.executeQuery()) {
|
||||
if (resultSet.next()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (Statement statement = adminConnection.createStatement()) {
|
||||
statement.execute("CREATE DATABASE " + quotePostgreSqlIdentifier(databaseName));
|
||||
} catch (SQLException ex) {
|
||||
if (isPostgreSqlAlreadyExists(ex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isPostgreSqlCreationPermissionIssue(ex)) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log(
|
||||
"No permission to create PostgreSQL database \"" + databaseName
|
||||
+ "\". Attempting to use the existing database instead."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPostgreSqlAlreadyExists(SQLException ex) {
|
||||
return ex instanceof PSQLException && "42P04".equals(ex.getSQLState());
|
||||
}
|
||||
|
||||
private static boolean isPostgreSqlCreationPermissionIssue(SQLException ex) {
|
||||
return "42501".equals(ex.getSQLState());
|
||||
}
|
||||
|
||||
private static String quotePostgreSqlIdentifier(String identifier) {
|
||||
return "\"" + identifier.replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
|
||||
public static void initH2() {
|
||||
initH2(true);
|
||||
}
|
||||
@@ -174,8 +258,9 @@ public class MySQL {
|
||||
if(conn instanceof NonClosableConnection) {
|
||||
((NonClosableConnection)conn).shutdown();
|
||||
} else conn.close();
|
||||
conn = null;
|
||||
}
|
||||
conn = null;
|
||||
Query.use(null);
|
||||
} catch (Exception e) {
|
||||
AntiVPN.getInstance().getExecutor().logException(e);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,17 @@ import java.sql.SQLException;
|
||||
public class Query {
|
||||
@Getter
|
||||
private static Connection conn;
|
||||
@Getter
|
||||
private static SqlDialect dialect = SqlDialect.GENERIC;
|
||||
|
||||
public static void use(Connection conn) {
|
||||
Query.conn = conn;
|
||||
Query.dialect = SqlDialect.from(conn);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SqlSourceToSinkFlow")
|
||||
public static ExecutableStatement prepare(@Language("SQL") String sql) throws SQLException {
|
||||
return new ExecutableStatement(conn.prepareStatement(sql));
|
||||
return new ExecutableStatement(conn.prepareStatement(dialect.translate(sql)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2026 Dawson Hessler
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.brighten.antivpn.database.sql.utils;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum SqlDialect {
|
||||
GENERIC,
|
||||
H2,
|
||||
MYSQL,
|
||||
POSTGRESQL;
|
||||
|
||||
public static SqlDialect from(Connection connection) {
|
||||
if (connection == null) {
|
||||
return GENERIC;
|
||||
}
|
||||
|
||||
try {
|
||||
String productName = connection.getMetaData().getDatabaseProductName();
|
||||
if (productName == null) {
|
||||
return GENERIC;
|
||||
}
|
||||
|
||||
return from(productName);
|
||||
} catch (SQLException ignored) {
|
||||
return GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
public static SqlDialect from(String productName) {
|
||||
String normalized = productName.toLowerCase(Locale.ROOT);
|
||||
if (normalized.contains("postgres")) {
|
||||
return POSTGRESQL;
|
||||
}
|
||||
if (normalized.contains("mysql")) {
|
||||
return MYSQL;
|
||||
}
|
||||
if (normalized.contains("h2")) {
|
||||
return H2;
|
||||
}
|
||||
return GENERIC;
|
||||
}
|
||||
|
||||
public boolean isPostgreSql() {
|
||||
return this == POSTGRESQL;
|
||||
}
|
||||
|
||||
public String translate(String sql) {
|
||||
if (!isPostgreSql()) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
String translated = sql.replace('`', '"');
|
||||
translated = translated.replaceAll(
|
||||
"(?i)\\bINT\\s+AUTO_INCREMENT\\s+PRIMARY\\s+KEY\\b",
|
||||
"INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY"
|
||||
);
|
||||
translated = translated.replaceAll("(?i)\\bAUTO_INCREMENT\\b", "GENERATED BY DEFAULT AS IDENTITY");
|
||||
translated = translated.replaceAll("(?i)\\bdouble\\b(?!\\s+precision)", "double precision");
|
||||
return translated;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import dev.brighten.antivpn.database.mongo.version.MongoFirst;
|
||||
import dev.brighten.antivpn.database.mongo.version.MongoSecond;
|
||||
import dev.brighten.antivpn.database.mongo.version.MongoThird;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.version.MySQLFirst;
|
||||
|
||||
|
||||
@@ -36,5 +37,6 @@ public interface Version<DB> {
|
||||
|
||||
Version<MongoVPN>[] mongoDbVersions = new Version[] {new MongoFirst(), new MongoSecond(), new MongoThird()};
|
||||
Version<MySqlVPN>[] mysqlVersions = new Version[] {new MySQLFirst(), new Second(), new Third()};
|
||||
Version<PostgreSqlVPN>[] postgresVersions = new Version[] {new First(), new Second(), new Third()};
|
||||
Version<H2VPN>[] h2Versions = new Version[] {new First(), new Second(), new Third()};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,9 @@ public final class LibraryLoader {
|
||||
return className;
|
||||
}
|
||||
|
||||
if (className.startsWith("com.mysql.cj") || className.startsWith("com.mysql.jdbc")) {
|
||||
if (className.startsWith("com.mysql.cj")
|
||||
|| className.startsWith("com.mysql.jdbc")
|
||||
|| className.startsWith("org.postgresql")) {
|
||||
return "dev.brighten.antivpn.shaded." + className;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ database:
|
||||
# Enable to cache queries and save alerts state beyond restarts
|
||||
enabled: true
|
||||
useCredentials: false
|
||||
#Options Mongo, MySQL, or H2
|
||||
#Options Mongo, MySQL, PostgreSQL, or H2
|
||||
type: H2
|
||||
# The database name you would like to use
|
||||
database: kaurivpn
|
||||
@@ -30,7 +30,7 @@ database:
|
||||
password: password
|
||||
# The IP of your database goes here
|
||||
ip: localhost
|
||||
# -1 will use default port of databases (MySQL:3306, Mongo:27017). Otherwise, enter alternative ports here.
|
||||
# -1 will use default port of databases (MySQL:3306, PostgreSQL:5432, Mongo:27017). Otherwise, enter an alternative port here.
|
||||
port: -1
|
||||
commands:
|
||||
# Enable this to override the default kick function of the plugin with your own commands
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Testcontainers
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class MongoDatabaseIntegrationTest extends DatabaseIntegrationTestSupport {
|
||||
|
||||
@Container
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Testcontainers
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class MySqlDatabaseIntegrationTest extends DatabaseIntegrationTestSupport {
|
||||
|
||||
@Container
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package dev.brighten.antivpn.database;
|
||||
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class PostgreSqlDatabaseIntegrationTest extends DatabaseIntegrationTestSupport {
|
||||
|
||||
@Container
|
||||
private static final PostgreSQLContainer<?> POSTGRES = new PostgreSQLContainer<>("postgres:16.3")
|
||||
.withDatabaseName("antivpn")
|
||||
.withUsername("testuser")
|
||||
.withPassword("testpass");
|
||||
|
||||
@Test
|
||||
void postgreSqlDatabaseImplementsTheVpnDatabaseContract() throws Exception {
|
||||
assertTrue(POSTGRES.isRunning(), "PostgreSQL Testcontainer should be running");
|
||||
|
||||
try (var connection = DriverManager.getConnection(
|
||||
POSTGRES.getJdbcUrl(),
|
||||
POSTGRES.getUsername(),
|
||||
POSTGRES.getPassword()
|
||||
);
|
||||
var statement = connection.createStatement();
|
||||
var resultSet = statement.executeQuery("SELECT 1")) {
|
||||
assertTrue(resultSet.next(), "Expected a row from the PostgreSQL container");
|
||||
assertEquals(1, resultSet.getInt(1), "Expected PostgreSQL container to respond to SELECT 1");
|
||||
}
|
||||
|
||||
when(vpnConfig.getIp()).thenReturn(POSTGRES.getHost());
|
||||
when(vpnConfig.getPort()).thenReturn(POSTGRES.getMappedPort(5432));
|
||||
when(vpnConfig.getDatabaseName()).thenReturn(POSTGRES.getDatabaseName());
|
||||
when(vpnConfig.getUsername()).thenReturn(POSTGRES.getUsername());
|
||||
when(vpnConfig.getPassword()).thenReturn(POSTGRES.getPassword());
|
||||
|
||||
assertDatabaseContract(new PostgreSqlVPN());
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ shadowJar {
|
||||
relocate 'com.mongodb', 'dev.brighten.antivpn.shaded.com.mongodb'
|
||||
relocate 'com.mysql.cj', 'dev.brighten.antivpn.shaded.com.mysql.cj'
|
||||
relocate 'com.mysql.jdbc', 'dev.brighten.antivpn.shaded.com.mysql.jdbc'
|
||||
relocate 'org.postgresql', 'dev.brighten.antivpn.shaded.org.postgresql'
|
||||
}
|
||||
|
||||
tasks.build.dependsOn shadowJar
|
||||
|
||||
+3
@@ -23,6 +23,7 @@ import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.mongo.MongoVPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.PostgreSqlVPN;
|
||||
import dev.brighten.antivpn.loader.LoaderBootstrap;
|
||||
import dev.brighten.antivpn.velocity.command.VelocityCommand;
|
||||
import lombok.Getter;
|
||||
@@ -61,6 +62,8 @@ public class VelocityPlugin implements LoaderBootstrap {
|
||||
VPNDatabase database = AntiVPN.getInstance().getDatabase();
|
||||
if(database instanceof MySqlVPN) {
|
||||
return "MySQL";
|
||||
} else if(database instanceof PostgreSqlVPN) {
|
||||
return "PostgreSQL";
|
||||
} else if(database instanceof H2VPN) {
|
||||
return "H2";
|
||||
} else if(database instanceof MongoVPN) {
|
||||
|
||||
@@ -16,6 +16,7 @@ allprojects {
|
||||
version = '1.10.0'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://repo.papermc.io/repository/maven-public/' }
|
||||
maven { url 'https://nexus.funkemunky.cc/repository/papermc-public/' }
|
||||
maven { url 'https://nexus.funkemunky.cc/repository/maven-public/' }
|
||||
|
||||
Reference in New Issue
Block a user