Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Automatically un-self-hoist users who try that #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/org/moss/discord/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.moss.discord.commands.VerifyCommand;
import org.moss.discord.commands.WolframAlphaCommand;
import org.moss.discord.commands.XkcdCommand;
import org.moss.discord.listeners.AntiHoistingListener;
import org.moss.discord.listeners.StarboardListener;
import org.moss.discord.commands.GithubCommand;
import org.moss.discord.commands.MojangCommand;
Expand Down Expand Up @@ -96,6 +97,7 @@ public static void main(String[] args) {
api.addListener(new AutoModListeners(api, commandHandler));
api.addListener(new PrivateListener(api));
api.addReactionAddListener(new StarboardListener(api));
api.addListener(new AntiHoistingListener(api));

}

Expand Down
141 changes: 141 additions & 0 deletions src/main/java/org/moss/discord/listeners/AntiHoistingListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.moss.discord.listeners;

import org.javacord.api.DiscordApi;
import org.javacord.api.entity.permission.PermissionType;
import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.server.ServerUpdater;
import org.javacord.api.entity.user.User;
import org.javacord.api.event.server.ServerJoinEvent;
import org.javacord.api.event.server.member.ServerMemberJoinEvent;
import org.javacord.api.event.user.UserChangeNameEvent;
import org.javacord.api.event.user.UserChangeNicknameEvent;
import org.javacord.api.listener.server.ServerJoinListener;
import org.javacord.api.listener.server.member.ServerMemberJoinListener;
import org.javacord.api.listener.user.UserChangeNameListener;
import org.javacord.api.listener.user.UserChangeNicknameListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.regex.Pattern;

/**
* Prevent users from setting annoying nicknames or real names.
*/
public class AntiHoistingListener implements UserChangeNameListener, UserChangeNicknameListener, ServerMemberJoinListener, ServerJoinListener {

private static final Logger LOGGER = LoggerFactory.getLogger(AntiHoistingListener.class);
private static final Pattern FORBIDDEN_NAMES = Pattern.compile("^[!*.,'($-]");
private static final String FORBIDDEN_NAME_REASON = "no self-hoisting :(";

private final DiscordApi api;

public AntiHoistingListener(DiscordApi api) {
this.api = api;
this.api.getServers().forEach(this::validateExistingServer);
}

// Event Listeners //

@Override
public void onServerJoin(ServerJoinEvent event) {
LOGGER.info("Joining server {}", event.getServer().getName());
validateExistingServer(event.getServer());
}

@Override
public void onServerMemberJoin(ServerMemberJoinEvent event) {
testAntiHoist(event.getServer(), event.getUser(),
event.getUser().getNickname(event.getServer()).orElse(event.getUser().getName()));
}

@Override
public void onUserChangeName(UserChangeNameEvent event) {
for (Server server : event.getUser().getMutualServers()) {
testAntiHoist(server, event.getUser(), event.getNewName());
}
}

@Override
public void onUserChangeNickname(UserChangeNicknameEvent event) {
final String nickname = event.getNewNickname().orElse(event.getUser().getName());
testAntiHoist(event.getServer(), event.getUser(), nickname);
}

// Detection logic //

private void validateExistingServer(final Server server) {
LOGGER.info("Validating server {}", server.getName());
ServerUpdater updater = null;
int updateCount = 0;
for (User user : server.getMembers()) {
if (shouldPreventHoist(server, user) && canManageUser(server, user)) {
if (updater == null) {
updater = server.createUpdater();
updater.setAuditLogReason(FORBIDDEN_NAME_REASON);
}
updater.setNickname(user, generateNickname(user));
updateCount++;
}
}
if (updater != null) {
int finalUpdateCount = updateCount;
updater.update().thenRun(() -> {
LOGGER.info("Successfully corrected the annoying names of {} users in {}", finalUpdateCount, server.getName());
}).exceptionally(err -> {
LOGGER.error("Unable to update user nicknames in {}", server.getName(), err);
return null;
});
}

}

private void testAntiHoist(final Server server, final User user, final String newNick) {
if (server.hasPermission(server.getApi().getYourself(), PermissionType.MANAGE_NICKNAMES) // can we change nicknames
&& FORBIDDEN_NAMES.matcher(newNick).lookingAt()) { // whoops
if (canManageUser(server, user)) {
server.updateNickname(user, generateNickname(user), FORBIDDEN_NAME_REASON);
}
// TODO: maybe notify users?
}
}

private boolean shouldPreventHoist(final Server server, final User user) {
final String nameOrNickname = user.getNickname(server).orElse(user.getName());
return server.hasPermission(server.getApi().getYourself(), PermissionType.MANAGE_NICKNAMES) // can we change nicknames
&& FORBIDDEN_NAMES.matcher(nameOrNickname).lookingAt(); // is this a bad nick

}

/**
* Get if the user has a role higher than the bot's highest role in the server.
*
* @param server server to check
* @param user user to check
* @return if things will go boom trying to do management things
*/
private boolean canManageUser(final Server server, final User user) {
int highestBotRole = -1;
int highestUserRole = -1;
final List<Role> roles = server.getRoles();
for (int i = roles.size() - 1; i >= 0; i--) { // highest role comes first
final Role role = roles.get(i);
if (role.hasUser(api.getYourself())) {
highestBotRole = Math.max(highestBotRole, role.getRawPosition());
}
if (role.hasUser(user)) {
highestUserRole = Math.max(highestUserRole, role.getRawPosition());
}

if (highestBotRole != -1 && highestUserRole != -1) {
break;
}
}
return highestBotRole >= highestUserRole;
}

private String generateNickname(final User user) {
return "zAnnoying name #" + Math.abs(user.getName().hashCode() % 10000);
}
}
18 changes: 9 additions & 9 deletions src/main/java/org/moss/discord/listeners/ModLogListeners.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void onMessageDelete(MessageDeleteEvent ev) {
embed.setFooter(ev.getMessage().get().getUserAuthor().get().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand All @@ -100,7 +100,7 @@ public void onMessageEdit(MessageEditEvent ev) {
embed.setFooter(ev.getMessage().get().getUserAuthor().get().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand Down Expand Up @@ -137,7 +137,7 @@ public void onServerMemberBan(ServerMemberBanEvent ev) {
embed.setFooter(ev.getUser().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand All @@ -153,7 +153,7 @@ public void onServerMemberJoin(ServerMemberJoinEvent ev) {
embed.setFooter(ev.getUser().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand Down Expand Up @@ -193,7 +193,7 @@ public void onServerMemberLeave(ServerMemberLeaveEvent ev) {

embed.setFooter(ev.getUser().getIdAsString());
embed.setTimestamp(Instant.now());
modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand All @@ -210,7 +210,7 @@ public void onUserChangeName(UserChangeNameEvent ev) {
embed.setFooter(ev.getUser().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

@Override
Expand All @@ -221,14 +221,14 @@ public void onUserChangeNickname(UserChangeNicknameEvent ev) {
embed.setColor(Color.YELLOW);
embed.setThumbnail("https://i.imgur.com/bYGnGCp.png");

embed.addInlineField("Old", ev.getOldNickname().get());
embed.addInlineField("New", ev.getNewNickname().get());
embed.addInlineField("Old", ev.getOldNickname().orElse("<none>"));
embed.addInlineField("New", ev.getNewNickname().orElse("<none>"));
embed.addField("ID", ev.getUser().getIdAsString());

embed.setFooter(ev.getUser().getIdAsString());
embed.setTimestamp(Instant.now());

modChannel.get().sendMessage(embed);
modChannel.ifPresent(ch -> ch.sendMessage(embed));
}

public String stripGrave(String string) {
Expand Down