trim the fat, hostname matching will bee too hard to set up for average user anyway
This commit is contained in:
@@ -5,7 +5,6 @@ public record DiscordInvite(
|
|||||||
Long guildId,
|
Long guildId,
|
||||||
Long expiresAt
|
Long expiresAt
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public DiscordInvite {
|
public DiscordInvite {
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
throw new IllegalArgumentException("Code cannot be null");
|
throw new IllegalArgumentException("Code cannot be null");
|
||||||
@@ -15,14 +14,4 @@ public record DiscordInvite(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the invite is expired.
|
|
||||||
* The invite is considered expired if the current time is more than 5 seconds before the expiration time.
|
|
||||||
*
|
|
||||||
* @return true if the invite is expired, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isExpired() {
|
|
||||||
return System.currentTimeMillis() + 5000 > expiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.time.temporal.ChronoUnit;
|
|||||||
public class DiscordInviteManager {
|
public class DiscordInviteManager {
|
||||||
|
|
||||||
private final Cache<String, DiscordInvite> cache = Caffeine.newBuilder()
|
private final Cache<String, DiscordInvite> cache = Caffeine.newBuilder()
|
||||||
.expireAfterWrite(Duration.of(60, ChronoUnit.SECONDS))
|
.expireAfterWrite(Duration.of(55, ChronoUnit.SECONDS))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private final JDA jda;
|
private final JDA jda;
|
||||||
@@ -26,7 +26,7 @@ public class DiscordInviteManager {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public DiscordInvite getInvite(long guildId) {
|
public DiscordInvite getInvite(long guildId) {
|
||||||
DiscordInvite discordInvite = cache.getIfPresent(String.valueOf(guildId));
|
DiscordInvite discordInvite = cache.getIfPresent(String.valueOf(guildId));
|
||||||
if (discordInvite == null || discordInvite.isExpired()) {
|
if (discordInvite == null) {
|
||||||
Guild guild = jda.getGuildById(guildId);
|
Guild guild = jda.getGuildById(guildId);
|
||||||
if (guild == null) {
|
if (guild == null) {
|
||||||
return null; // Guild not found
|
return null; // Guild not found
|
||||||
@@ -48,4 +48,8 @@ public class DiscordInviteManager {
|
|||||||
return discordInvite;
|
return discordInvite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeFromCache(long guildId) {
|
||||||
|
cache.invalidate(String.valueOf(guildId));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package me.youhavetrouble.inviter.discord;
|
package me.youhavetrouble.inviter.discord;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public record GuildSettings(
|
public record GuildSettings(
|
||||||
long guildId,
|
long guildId,
|
||||||
boolean apiEnabled,
|
boolean apiEnabled
|
||||||
@Nullable String apiHostname
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ public class ApiStatusChangeCommand extends Command {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "api";
|
return "invites";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(JDA jda, String name) {
|
public void register(JDA jda, String name) {
|
||||||
jda.upsertCommand(Commands.slash("api", "Change if Inviter API should allow to retrieve this server's invites.")
|
jda.upsertCommand(Commands.slash("invites", "Change or see if Inviter should create invites for this guild.")
|
||||||
.setIntegrationTypes(IntegrationType.GUILD_INSTALL)
|
.setIntegrationTypes(IntegrationType.GUILD_INSTALL)
|
||||||
.addOptions(
|
.addOptions(
|
||||||
new OptionData(OptionType.BOOLEAN, "status", "Status of the api availability for this guild", false)
|
new OptionData(OptionType.BOOLEAN, "status", "Enable or disable Inviter to work for this guild", false)
|
||||||
)
|
)
|
||||||
.setContexts(InteractionContextType.GUILD)
|
.setContexts(InteractionContextType.GUILD)
|
||||||
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
||||||
@@ -49,8 +49,8 @@ public class ApiStatusChangeCommand extends Command {
|
|||||||
GuildSettings setings = Main.getStorage().getGuildSettings(guild.getIdLong());
|
GuildSettings setings = Main.getStorage().getGuildSettings(guild.getIdLong());
|
||||||
|
|
||||||
String message = setings.apiEnabled() ?
|
String message = setings.apiEnabled() ?
|
||||||
"Inviter API is currently __**enabled**__ for this server." :
|
"Inviter is currently __**enabled**__ for this server." :
|
||||||
"Inviter API is currently __**disabled**__ for this server.";
|
"Inviter is currently __**disabled**__ for this server.";
|
||||||
|
|
||||||
event.getHook().editOriginal(message).queue();
|
event.getHook().editOriginal(message).queue();
|
||||||
return;
|
return;
|
||||||
@@ -59,8 +59,8 @@ public class ApiStatusChangeCommand extends Command {
|
|||||||
boolean status = statusMapping.getAsBoolean();
|
boolean status = statusMapping.getAsBoolean();
|
||||||
long guildId = guild.getIdLong();
|
long guildId = guild.getIdLong();
|
||||||
|
|
||||||
Main.getStorage().updateDiscordApiEnabled(guildId, status);
|
Main.getStorage().updateInvitesEnabled(guildId, status);
|
||||||
String message = status ? "Inviter API is now __**enabled**__ for this server." : "Inviter API is now __**disabled**__ for this server.";
|
String message = status ? "Inviter is now __**enabled**__ for this server." : "Inviter API is now __**disabled**__ for this server.";
|
||||||
event.getHook().editOriginal(message).queue();
|
event.getHook().editOriginal(message).queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -19,9 +19,9 @@ public class GuildJoinAndLeaveListener extends ListenerAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGuildLeave(@NotNull GuildLeaveEvent event) {
|
public void onGuildLeave(@NotNull GuildLeaveEvent event) {
|
||||||
Storage storage = Main.getStorage();
|
|
||||||
long guildId = event.getGuild().getIdLong();
|
long guildId = event.getGuild().getIdLong();
|
||||||
storage.removeGuildSettings(guildId);
|
Main.getDiscordInviteMenager().removeFromCache(guildId);
|
||||||
|
Main.getStorage().removeGuildSettings(guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package me.youhavetrouble.inviter.dns;
|
|
||||||
|
|
||||||
import me.youhavetrouble.inviter.Main;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.naming.directory.Attribute;
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.directory.InitialDirContext;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class DNSLookup {
|
|
||||||
|
|
||||||
public static Set<String> getTxtRecords(@NotNull String hostname) throws Exception {
|
|
||||||
Hashtable<String, String> env = new Hashtable<>();
|
|
||||||
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
|
|
||||||
env.put("java.naming.provider.url", "dns://1.1.1.1");
|
|
||||||
env.put("com.sun.jndi.dns.cache.ttl", "0");
|
|
||||||
Set<String> txtRecords = new HashSet<>();
|
|
||||||
|
|
||||||
DirContext ctx = new InitialDirContext(env);
|
|
||||||
Attributes attrs = ctx.getAttributes(hostname, new String[]{"TXT"});
|
|
||||||
Attribute txtAttr = attrs.get("TXT");
|
|
||||||
|
|
||||||
if (txtAttr != null) {
|
|
||||||
for (int i = 0; i < txtAttr.size(); i++) {
|
|
||||||
Object record = txtAttr.get(i);
|
|
||||||
if (record instanceof String recordString) {
|
|
||||||
txtRecords.add(recordString);
|
|
||||||
} else if (record instanceof byte[]) {
|
|
||||||
txtRecords.add(new String((byte[]) record));
|
|
||||||
} else {
|
|
||||||
txtRecords.add(record.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return txtRecords;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -11,7 +11,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
public class GetDiscordInviteByGuildId implements EndpointHandler {
|
public class GetDiscordInviteByGuildId implements EndpointHandler {
|
||||||
|
|
||||||
private final Pattern pathPattern = Pattern.compile("^/api/v1/discord/\\d{10,18}$");
|
private final Pattern pathPattern = Pattern.compile("^/invite/\\d{10,18}$");
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package me.youhavetrouble.inviter.http.endpoints;
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
|
||||||
import me.youhavetrouble.inviter.Main;
|
|
||||||
import me.youhavetrouble.inviter.discord.DiscordInvite;
|
|
||||||
import me.youhavetrouble.inviter.discord.DiscordInviteManager;
|
|
||||||
import me.youhavetrouble.inviter.discord.GuildSettings;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class MainEndpoint implements EndpointHandler {
|
|
||||||
|
|
||||||
private final Pattern pathPattern = Pattern.compile("^/$");
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Pattern pathPattern() {
|
|
||||||
return pathPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(@NotNull HttpExchange exchange) throws IOException {
|
|
||||||
if (!exchange.getRequestMethod().equals("GET")) {
|
|
||||||
exchange.sendResponseHeaders(405, -1); // Method Not Allowed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String host = exchange.getRemoteAddress().getHostName();
|
|
||||||
|
|
||||||
GuildSettings guildSettings = Main.getStorage().getGuildSettings(host);
|
|
||||||
if (guildSettings == null) {
|
|
||||||
exchange.sendResponseHeaders(404, -1); // Not Found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DiscordInviteManager inviteManager = Main.getDiscordInviteMenager();
|
|
||||||
DiscordInvite invite = inviteManager.getInvite(guildSettings.guildId());
|
|
||||||
|
|
||||||
if (invite == null) {
|
|
||||||
exchange.sendResponseHeaders(404, -1); // Not Found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
exchange.getResponseHeaders().set("Location", "https://discord.gg/" + invite.code());
|
|
||||||
exchange.sendResponseHeaders(307, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ import com.zaxxer.hikari.HikariConfig;
|
|||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import me.youhavetrouble.inviter.discord.GuildSettings;
|
import me.youhavetrouble.inviter.discord.GuildSettings;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -12,7 +11,6 @@ import java.sql.Connection;
|
|||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SqliteStorage implements Storage {
|
public class SqliteStorage implements Storage {
|
||||||
|
|
||||||
@@ -39,18 +37,10 @@ public class SqliteStorage implements Storage {
|
|||||||
connection.createStatement().execute("""
|
connection.createStatement().execute("""
|
||||||
CREATE TABLE IF NOT EXISTS guild_settings (
|
CREATE TABLE IF NOT EXISTS guild_settings (
|
||||||
guild_id LONG PRIMARY KEY,
|
guild_id LONG PRIMARY KEY,
|
||||||
api_enabled BOOLEAN NOT NULL DEFAULT FALSE
|
invites_enabled BOOLEAN NOT NULL DEFAULT FALSE
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
connection.createStatement().execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS hostnames (
|
|
||||||
hostname VARCHAR(256) PRIMARY KEY,
|
|
||||||
guild_id LONG NOT NULL,
|
|
||||||
failed_checks INTEGER NOT NULL DEFAULT 0,
|
|
||||||
FOREIGN KEY (guild_id) REFERENCES guild_settings(guild_id) ON DELETE CASCADE
|
|
||||||
)
|
|
||||||
""");
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException("Failed to initialize database", e);
|
throw new RuntimeException("Failed to initialize database", e);
|
||||||
}
|
}
|
||||||
@@ -69,39 +59,16 @@ public class SqliteStorage implements Storage {
|
|||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
boolean apiEnabled = resultSet.getBoolean("api_enabled");
|
boolean invitesEnabled = resultSet.getBoolean("invites_enabled");
|
||||||
String apiHostname = resultSet.getString("hostname");
|
return new GuildSettings(guildId, invitesEnabled);
|
||||||
return new GuildSettings(guildId, apiEnabled, apiHostname);
|
|
||||||
}
|
}
|
||||||
return new GuildSettings(guildId,false, null);
|
return new GuildSettings(guildId,false);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException("Failed to retrieve guild settings", e);
|
throw new RuntimeException("Failed to retrieve guild settings", e);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public GuildSettings getGuildSettings(@NotNull String hostname) {
|
|
||||||
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
|
||||||
"SELECT * FROM guild_settings WHERE hostname = ?"
|
|
||||||
);
|
|
||||||
statement.setString(1, hostname);
|
|
||||||
ResultSet resultSet = statement.executeQuery();
|
|
||||||
|
|
||||||
if (resultSet.next()) {
|
|
||||||
long guildId = resultSet.getLong("guild_id");
|
|
||||||
boolean apiEnabled = resultSet.getBoolean("api_enabled");
|
|
||||||
return new GuildSettings(guildId, apiEnabled, hostname);
|
|
||||||
}
|
|
||||||
return null; // No settings found for the given hostname
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException("Failed to retrieve guild settings by hostname", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveDefaultGuildSettings(long guildId) {
|
public void saveDefaultGuildSettings(long guildId) {
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
@@ -129,10 +96,10 @@ public class SqliteStorage implements Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDiscordApiEnabled(long guildId, boolean enabled) {
|
public void updateInvitesEnabled(long guildId, boolean enabled) {
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
PreparedStatement statement = connection.prepareStatement(
|
||||||
"UPDATE guild_settings SET api_enabled = ? WHERE guild_id = ?"
|
"UPDATE guild_settings SET invites_enabled = ? WHERE guild_id = ?"
|
||||||
);
|
);
|
||||||
statement.setBoolean(1, enabled);
|
statement.setBoolean(1, enabled);
|
||||||
statement.setLong(2, guildId);
|
statement.setLong(2, guildId);
|
||||||
@@ -143,63 +110,4 @@ public class SqliteStorage implements Storage {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addHostname(long guildId, @Nullable String hostname) {
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
|
||||||
"INSERT OR IGNORE INTO hostnames (hostname, guild_id) VALUES (?, ?)"
|
|
||||||
);
|
|
||||||
statement.setString(1, hostname);
|
|
||||||
statement.setLong(2, guildId);
|
|
||||||
statement.executeUpdate();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException("Failed to add hostname", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeHostname(@NotNull String hostname) {
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
|
||||||
"DELETE FROM hostnames WHERE hostname = ?"
|
|
||||||
);
|
|
||||||
statement.setString(1, hostname);
|
|
||||||
statement.executeUpdate();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException("Failed to remove hostname", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> listHostnames(long guildId) {
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
|
||||||
"SELECT hostname FROM hostnames WHERE guild_id = ?"
|
|
||||||
);
|
|
||||||
statement.setLong(1, guildId);
|
|
||||||
ResultSet resultSet = statement.executeQuery();
|
|
||||||
|
|
||||||
List<String> hostnames = new java.util.ArrayList<>();
|
|
||||||
while (resultSet.next()) {
|
|
||||||
hostnames.add(resultSet.getString("hostname"));
|
|
||||||
}
|
|
||||||
return hostnames;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException("Failed to list hostnames", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cleanUpHostnames() {
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
|
||||||
PreparedStatement statement = connection.prepareStatement(
|
|
||||||
"DELETE FROM hostnames WHERE failed_checks >= 3"
|
|
||||||
);
|
|
||||||
statement.executeUpdate();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new RuntimeException("Failed to clean up hostnames", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,28 +3,15 @@ package me.youhavetrouble.inviter.storage;
|
|||||||
|
|
||||||
import me.youhavetrouble.inviter.discord.GuildSettings;
|
import me.youhavetrouble.inviter.discord.GuildSettings;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface Storage {
|
public interface Storage {
|
||||||
|
|
||||||
@NotNull GuildSettings getGuildSettings(long guildId);
|
@NotNull GuildSettings getGuildSettings(long guildId);
|
||||||
|
|
||||||
@Nullable GuildSettings getGuildSettings(@NotNull String hostname);
|
|
||||||
|
|
||||||
void saveDefaultGuildSettings(long guildId);
|
void saveDefaultGuildSettings(long guildId);
|
||||||
|
|
||||||
void removeGuildSettings(long guildId);
|
void removeGuildSettings(long guildId);
|
||||||
|
|
||||||
void updateDiscordApiEnabled(long guildId, boolean enabled);
|
void updateInvitesEnabled(long guildId, boolean enabled);
|
||||||
|
|
||||||
void addHostname(long guildId, @Nullable String hostname);
|
|
||||||
|
|
||||||
void removeHostname(@NotNull String hostname);
|
|
||||||
|
|
||||||
List<String> listHostnames(long guildId);
|
|
||||||
|
|
||||||
void cleanUpHostnames();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user