mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-14 11:48:16 +00:00
[AB-71] adding very simple anti raid feature to automatically mute member who mass mention users
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>anti-raid-impl</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>anti-raid-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/liquibase.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
|
||||
<id>liquibase</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>.</outputDirectory>
|
||||
<directory>${project.basedir}/src/main/resources/migrations</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.antiraid.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:antiRaid-config.properties")
|
||||
public class AntiRaidProperties {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dev.sheldan.abstracto.antiraid.listener;
|
||||
|
||||
import dev.sheldan.abstracto.antiraid.config.AntiRaidFeatureDefinition;
|
||||
import dev.sheldan.abstracto.antiraid.service.MassPingService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.ChannelType;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MassPingMessageListener implements AsyncMessageReceivedListener {
|
||||
|
||||
@Autowired
|
||||
private MassPingService massPingService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageReceivedModel model) {
|
||||
Message message = model.getMessage();
|
||||
if(message.getAuthor().isBot() || message.isWebhookMessage() || !message.isFromGuild() || !message.isFromType(ChannelType.TEXT)) {
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
massPingService.processMessage(message);
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return AntiRaidFeatureDefinition.ANTI_RAID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package dev.sheldan.abstracto.antiraid.service;
|
||||
|
||||
import dev.sheldan.abstracto.antiraid.config.AntiRaidPostTarget;
|
||||
import dev.sheldan.abstracto.antiraid.model.MassPingNotificationModel;
|
||||
import dev.sheldan.abstracto.core.models.ConditionContextInstance;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ConditionService;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.PostTargetService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.moderation.service.MuteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MassPingServiceBean implements MassPingService {
|
||||
|
||||
private static final String MASS_PING_MUTE_NOTIFICATION_TEMPLATE_KEY = "massPing_mute_notification";
|
||||
|
||||
private static final String LEVEL_CONDITION_NAME = "HAS_LEVEL";
|
||||
private static final String LEVEL_CONDITION_USER_ID_PARAMETER = "userId";
|
||||
private static final String LEVEL_CONDITION_LEVEL_PARAMETER = "level";
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private MuteService muteService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private MassPingServiceBean self;
|
||||
|
||||
@Autowired
|
||||
private PostTargetService postTargetService;
|
||||
|
||||
@Autowired
|
||||
private ConditionService conditionService;
|
||||
|
||||
@Value("${abstracto.massPing.maxAllowedMentions}")
|
||||
private Integer maxAllowedMentions;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> processMessage(Message message) {
|
||||
if(message.getMentionedMembers().size() > maxAllowedMentions) {
|
||||
Integer level = configService.getLongValueOrConfigDefault(MassPingService.MAX_AFFECTED_LEVEL_KEY, message.getGuild().getIdLong()).intValue();
|
||||
boolean allowed = allowedToMassMention(message, level);
|
||||
if(!allowed) {
|
||||
return muteService.muteMemberWithoutContext(message.getMember())
|
||||
.thenAccept(unused -> self.sendMassPingMuteNotification(message))
|
||||
.thenAccept(unused -> log.info("Muted member {} in server {} because of too many member mentions. (> {}).",
|
||||
message.getMember().getIdLong(), message.getGuild().getIdLong(), maxAllowedMentions));
|
||||
} else {
|
||||
log.info("User {} in server {} is allowed to mass mention, because of level (or lack of level configuration).",
|
||||
message.getMember().getIdLong(), message.getGuild().getIdLong());
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allowedToMassMention(Message message, Integer level) {
|
||||
log.info("Checking if member {} is allowed to mention a lot of users in server {}.", message.getAuthor().getIdLong(), message.getGuild().getIdLong());
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(message.getMember());
|
||||
parameters.put(LEVEL_CONDITION_USER_ID_PARAMETER, userInAServer.getUserInServerId());
|
||||
parameters.put(LEVEL_CONDITION_LEVEL_PARAMETER, level);
|
||||
ConditionContextInstance contextInstance = ConditionContextInstance
|
||||
.builder()
|
||||
.conditionName(LEVEL_CONDITION_NAME)
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
return conditionService.checkConditions(contextInstance);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> sendMassPingMuteNotification(Message message) {
|
||||
Member member = message.getMember();
|
||||
MassPingNotificationModel model = MassPingNotificationModel
|
||||
.builder()
|
||||
.messageLink(message.getJumpUrl())
|
||||
.mentionCount(message.getMentionedMembers().size())
|
||||
.messageContent(message.getContentRaw())
|
||||
.memberDisplay(MemberDisplay.fromMember(member))
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MASS_PING_MUTE_NOTIFICATION_TEMPLATE_KEY, model, member.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, AntiRaidPostTarget.MASS_PING_LOG, member.getGuild().getIdLong()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
abstracto.featureFlags.antiRaid.featureName=antiRaid
|
||||
abstracto.featureFlags.antiRaid.enabled=false
|
||||
|
||||
abstracto.postTargets.massPingLog.name=massPingLog
|
||||
|
||||
abstracto.massPing.maxAllowedMentions=5
|
||||
|
||||
abstracto.systemConfigs.massPingMinLevel.name=massPingMinLevel
|
||||
abstracto.systemConfigs.massPingMinLevel.longValue=15
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="feature.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="anti_raid-feature-insertion">
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="antiRaid"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="1.3.3/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user