Skip to content

Commit f145ab6

Browse files
committed
Automate applying security actions
1 parent 9a0fd32 commit f145ab6

5 files changed

Lines changed: 127 additions & 1 deletion

File tree

src/main/java/org/geysermc/discordbot/GeyserBot.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import net.dv8tion.jda.api.utils.MemberCachePolicy;
4343
import net.dv8tion.jda.api.utils.cache.CacheFlag;
4444
import net.dv8tion.jda.api.utils.messages.MessageRequest;
45+
import org.geysermc.discordbot.background.SecurityActionsApplier;
4546
import org.geysermc.discordbot.health_checker.HealthCheckerManager;
4647
import org.geysermc.discordbot.http.Server;
4748
import org.geysermc.discordbot.listeners.*;
@@ -301,6 +302,9 @@ public static void main(String[] args) throws IOException {
301302
int playerCount = players.getJSONArray(players.length() - 1).getInt(1);
302303
jda.getPresence().setActivity(Activity.playing(BotHelpers.coolFormat(serverCount) + " servers, " + BotHelpers.coolFormat(playerCount) + " players"));
303304
}, 5, 60 * 5, TimeUnit.SECONDS);
305+
306+
// Start the Security Actions applier
307+
generalThreadPool.scheduleAtFixedRate(new SecurityActionsApplier(), 5, 60 * 60, TimeUnit.SECONDS);
304308
}
305309

306310
public static JDA getJDA() {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2026 GeyserMC. http://geysermc.org
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*
22+
* @author GeyserMC
23+
* @link https://github.com/GeyserMC/GeyserDiscordBot
24+
*/
25+
26+
package org.geysermc.discordbot.background;
27+
28+
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
29+
import java.time.OffsetDateTime;
30+
import java.util.List;
31+
import net.dv8tion.jda.api.Permission;
32+
import net.dv8tion.jda.api.entities.Guild;
33+
import net.dv8tion.jda.api.entities.guild.SecurityIncidentActions;
34+
import org.geysermc.discordbot.GeyserBot;
35+
import org.geysermc.discordbot.storage.ServerSettings;
36+
37+
public class SecurityActionsApplier implements Runnable {
38+
@Override
39+
public void run() {
40+
Long2ObjectMap<List<String>> enabledActionsPerGuild = ServerSettings.getListForAllServers("security-actions");
41+
if (enabledActionsPerGuild.isEmpty()) {
42+
return;
43+
}
44+
45+
// The max is 24h, so just set it to 12h to be sure.
46+
// It runs every hour anyway.
47+
OffsetDateTime later = OffsetDateTime.now().plusHours(12);
48+
49+
for (Long2ObjectMap.Entry<List<String>> entry : enabledActionsPerGuild.long2ObjectEntrySet()) {
50+
Guild guild = GeyserBot.getJDA().getGuildById(entry.getLongKey());
51+
if (guild == null || !guild.getSelfMember().hasPermission(Permission.MANAGE_SERVER)) continue;
52+
53+
boolean invitesDisabled = entry.getValue().contains("invites");
54+
boolean dmsDisabled = entry.getValue().contains("dms");
55+
56+
if (invitesDisabled || dmsDisabled) {
57+
guild.modifySecurityIncidents(SecurityIncidentActions.enabled(
58+
invitesDisabled ? later : null,
59+
dmsDisabled ? later : null
60+
)).queue();
61+
continue;
62+
}
63+
64+
SecurityIncidentActions actions = guild.getSecurityIncidentActions();
65+
if (actions.getDirectMessagesDisabledUntil() != null || actions.getInvitesDisabledUntil() != null) {
66+
guild.modifySecurityIncidents(SecurityIncidentActions.disabled()).queue();
67+
}
68+
}
69+
}
70+
}

src/main/java/org/geysermc/discordbot/storage/AbstractStorageManager.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525

2626
package org.geysermc.discordbot.storage;
2727

28+
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
2829
import net.dv8tion.jda.api.entities.Guild;
2930
import net.dv8tion.jda.api.entities.Member;
3031
import net.dv8tion.jda.api.entities.Role;
31-
import net.dv8tion.jda.api.entities.User;
3232
import net.dv8tion.jda.api.entities.UserSnowflake;
3333
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
3434

@@ -55,6 +55,14 @@ public abstract class AbstractStorageManager {
5555
*/
5656
public abstract String getServerPreference(long serverID, String preference);
5757

58+
/**
59+
* Get a preference from the database, for all servers
60+
*
61+
* @param preference Key of the requested preference
62+
* @return The value for each server that has configured this preference.
63+
*/
64+
public abstract Long2ObjectMap<String> getPreferenceForAllServers(String preference);
65+
5866
/**
5967
* Set a preference in the database
6068
*

src/main/java/org/geysermc/discordbot/storage/MySQLStorageManager.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
package org.geysermc.discordbot.storage;
2727

2828

29+
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
30+
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
31+
import java.sql.PreparedStatement;
2932
import net.dv8tion.jda.api.entities.Guild;
3033
import net.dv8tion.jda.api.entities.Member;
3134
import net.dv8tion.jda.api.entities.Role;
@@ -99,6 +102,24 @@ public String getServerPreference(long serverID, String preference) {
99102
return null;
100103
}
101104

105+
@Override
106+
public Long2ObjectMap<String> getPreferenceForAllServers(String preference) {
107+
checkConnection();
108+
try (PreparedStatement statement = connection.prepareStatement("SELECT server, value FROM preferences WHERE key = ?")) {
109+
statement.setString(1, preference);
110+
111+
Long2ObjectMap<String> map = new Long2ObjectOpenHashMap<>();
112+
try (ResultSet result = statement.executeQuery()) {
113+
while (result.next()) {
114+
map.put(result.getLong(1), result.getString(2));
115+
}
116+
}
117+
return map;
118+
} catch (SQLException ignored) {
119+
return null;
120+
}
121+
}
122+
102123
@Override
103124
public void setServerPreference(long serverID, String preference, String value) {
104125
checkConnection();

src/main/java/org/geysermc/discordbot/storage/ServerSettings.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525

2626
package org.geysermc.discordbot.storage;
2727

28+
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
29+
import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
30+
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
2831
import net.dv8tion.jda.api.entities.Guild;
2932
import net.dv8tion.jda.api.entities.Role;
3033
import net.dv8tion.jda.api.entities.channel.Channel;
@@ -69,6 +72,26 @@ public static List<String> getList(long serverID, String key) {
6972
return new ArrayList<>(Arrays.asList(listData.split(",").clone()));
7073
}
7174

75+
/**
76+
* Get a preference as a list of strings delimited by `,`, for each server with this preference
77+
*
78+
* @param key The preference key to get
79+
* @return Per guild the preference value as a list
80+
*/
81+
@NotNull
82+
public static Long2ObjectMap<List<String>> getListForAllServers(String key) {
83+
Long2ObjectMap<String> listData = GeyserBot.storageManager.getPreferenceForAllServers(key);
84+
if (listData == null) {
85+
return Long2ObjectMaps.emptyMap();
86+
}
87+
88+
Long2ObjectMap<List<String>> map = new Long2ObjectOpenHashMap<>();
89+
listData.long2ObjectEntrySet().forEach(entry ->
90+
map.put(entry.getLongKey(), new ArrayList<>(Arrays.asList(entry.getValue().split(",").clone())))
91+
);
92+
return map;
93+
}
94+
7295
public static void setList(long serverID, String key, List<String> data) {
7396
GeyserBot.storageManager.setServerPreference(serverID, key, StringUtils.join(data, ","));
7497
}

0 commit comments

Comments
 (0)