Commit 8387e88e authored by Adam Gausmann's avatar Adam Gausmann

Merge branch 'mask' into 'master'

Implementation of user masks

This provides a much better way to identify users by parsing and checking user masks (a combination of nickname, username, and hostname) instead of just nicknames.

See merge request !13
parents c82abda7 1112c682
Pipeline #4303892 passed with stages
in 11 seconds
package ninja.nonemu.samurai.command;
import ninja.nonemu.samurai.connection.UserMask;
/**
* Defines a command system that registers commands and sends them to executors.
* @see CommandInfo
......@@ -33,42 +35,42 @@ public interface CommandSystem {
/**
* Determines whether the command sender is allowed to run privileged commands.
*
* @param name The name of the sender to check.
* @param mask The mask of the sender to check.
* @return true if the sender is an operator; false otherwise.
*/
boolean isOperator(String name);
boolean isOperator(UserMask mask);
/**
* Adds a sender to the operator list. Any sender with that name can run privileged commands.
* @param name The name to add.
* Adds a sender to the operator list. Any sender with that mask can run privileged commands.
* @param mask The mask to add.
*/
void addOperator(String name);
void addOperator(UserMask mask);
/**
* Removes a sender from the operator list. If they previously had privileges, they won't anymore.
* @param name The name to remove.
* @param mask The mask to remove.
*/
void removeOperator(String name);
void removeOperator(UserMask mask);
/**
* Determines whether the command sender is allowed to run commands when the bot's whitelist is enabled.
*
* @param name The name of the sender to check.
* @param mask The mask of the sender to check.
* @return true if the sender is whitelisted; false otherwise.
*/
boolean isWhitelisted(String name);
boolean isWhitelisted(UserMask mask);
/**
* Adds a sender to the whitelist. Any sender with that name can run commands when whitelist is enabled.
* @param name The name to add.
* Adds a sender to the whitelist. Any sender with that mask can run commands when whitelist is enabled.
* @param mask The mask to add.
*/
void addWhitelisted(String name);
void addWhitelisted(UserMask mask);
/**
* Removes a sender from the whitelist. If they previously had privileges, they won't anymore.
* @param name The name to remove.
* @param mask The mask to remove.
*/
void removeWhitelisted(String name);
void removeWhitelisted(UserMask mask);
boolean isWhitelistEnabled();
......@@ -77,20 +79,20 @@ public interface CommandSystem {
/**
* Determines whether the command sender is banned from using commands.
*
* @param name The name of the sender to check.
* @param mask The mask of the sender to check.
* @return true if the sender is blacklisted; false otherwise.
*/
boolean isBlacklisted(String name);
boolean isBlacklisted(UserMask mask);
/**
* Adds a sender to the blacklist. Any sender with that name cannot run commands at all.
* @param name The name to add.
* Adds a sender to the blacklist. Any sender with that mask cannot run commands at all.
* @param mask The mask to add.
*/
void addBlacklisted(String name);
void addBlacklisted(UserMask mask);
/**
* Removes a sender from the blacklist. If they previosuly didn't have privileges, they will now.
* @param name The name to remove.
* Removes a sender from the blacklist. If they previously didn't have privileges, they will now.
* @param mask The mask to remove.
*/
void removeBlacklisted(String name);
void removeBlacklisted(UserMask mask);
}
......@@ -82,6 +82,8 @@ public interface ConnectionManager {
User getUser(String userId);
User getUser(UserMask userMask);
/**
* Gets the currently-configured host that the client is connecting to.
*/
......
package ninja.nonemu.samurai.connection;
import java.io.IOException;
import ninja.nonemu.irc.ChatRecipient;
import ninja.nonemu.irc.ChatSender;
import ninja.nonemu.samurai.command.CommandSender;
public interface User extends ChatSender, ChatRecipient, CommandSender {
String getName();
default String getName() {
return getNickname();
}
ninja.nonemu.irc.User moreInfo() throws IOException;
UserMask getMask();
String getNickname();
String getUsername();
String getHostname();
}
package ninja.nonemu.samurai.connection;
public class UserMask implements Comparable<UserMask> {
private final String mask;
public UserMask(String mask) {
this.mask = mask;
}
public String getNickname() {
if (mask.contains("!")) {
return mask.substring(0, mask.indexOf("!"));
}
return mask;
}
public String getUsername() {
if (mask.contains("!")) {
if (mask.contains("@")) {
return mask.substring(mask.indexOf("!") + 1, mask.indexOf("@"));
}
return mask.substring(mask.indexOf("!") + 1);
}
return null;
}
public String getHostname() {
if (mask.contains("@")) {
return mask.substring(mask.indexOf("@") + 1);
}
return null;
}
public boolean isWildcard() {
return mask.contains("*") || mask.contains("?");
}
public String getMask() {
return mask;
}
public boolean matches(UserMask mask) {
return matches(getNickname(), mask.getNickname()) && matches(getUsername(), mask.getUsername())
&& matches(getHostname(), mask.getHostname());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UserMask)) return false;
UserMask userMask = (UserMask) o;
return mask.equalsIgnoreCase(userMask.mask);
}
@Override
public int hashCode() {
return mask.toLowerCase().hashCode();
}
private static boolean matches(String a, String b) {
if (a == null || b == null) {
return true;
}
a = a.toLowerCase();
b = b.toLowerCase();
if (a.equals(b)) {
return true;
}
String pA = "^" + a.replace(".", "\\.").replace("*", ".*").replace("?", ".") + "$";
String pB = "^" + b.replace(".", "\\.").replace("*", ".*").replace("?", ".") + "$";
return a.matches(pB) || b.matches(pA);
}
@Override
public int compareTo(UserMask o) {
return String.CASE_INSENSITIVE_ORDER.compare(mask, o.mask);
}
@Override
public String toString() {
return mask;
}
}
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import ninja.nonemu.samurai.BotImpl;
import ninja.nonemu.samurai.connection.UserMask;
public class CommandExecutorImpl {
private final BotImpl bot;
......@@ -125,13 +126,13 @@ public class CommandExecutorImpl {
}
if (args[0].equalsIgnoreCase("add")) {
bot.getCommandSystem().addOperator(args[1]);
sender.sendChat("User " + args[1] + " added as an operator.");
bot.getCommandSystem().addOperator(new UserMask(args[1]));
sender.sendChat(args[1] + " has been added as an operator.");
return true;
}
if (args[0].equalsIgnoreCase("remove")) {
bot.getCommandSystem().removeOperator(args[1]);
sender.sendChat("User " + args[1] + " removed from operator status.");
bot.getCommandSystem().removeOperator(new UserMask(args[1]));
sender.sendChat(args[1] + " has been removed from operator status.");
return true;
}
return false;
......@@ -146,16 +147,16 @@ public class CommandExecutorImpl {
if (args.length < 2) {
return false;
}
bot.getCommandSystem().addWhitelisted(args[1]);
sender.sendChat("User " + args[1] + " added to the whitelist.");
bot.getCommandSystem().addWhitelisted(new UserMask(args[1]));
sender.sendChat(args[1] + " has been added to the whitelist.");
return true;
}
if (args[0].equalsIgnoreCase("remove")) {
if (args.length < 2) {
return false;
}
bot.getCommandSystem().removeWhitelisted(args[1]);
sender.sendChat("User " + args[1] + " removed from the whitelist.");
bot.getCommandSystem().removeWhitelisted(new UserMask(args[1]));
sender.sendChat(args[1] + " has been removed from the whitelist.");
return true;
}
if (args[0].equalsIgnoreCase("enable")) {
......@@ -177,13 +178,13 @@ public class CommandExecutorImpl {
}
if (args[0].equalsIgnoreCase("add")) {
bot.getCommandSystem().addBlacklisted(args[1]);
sender.sendChat("User " + args[1] + " added to the blaclklist.");
bot.getCommandSystem().addBlacklisted(new UserMask(args[1]));
sender.sendChat(args[1] + " has been added to the blaclklist.");
return true;
}
if (args[0].equalsIgnoreCase("remove")) {
bot.getCommandSystem().removeBlacklisted(args[1]);
sender.sendChat("User " + args[1] + " removed from the blacklist.");
bot.getCommandSystem().removeBlacklisted(new UserMask(args[1]));
sender.sendChat(args[1] + " has been removed from the blacklist.");
return true;
}
return false;
......
......@@ -15,6 +15,7 @@ import java.util.TreeSet;
import ninja.nonemu.samurai.BotImpl;
import ninja.nonemu.samurai.connection.ChatEvent;
import ninja.nonemu.samurai.connection.User;
import ninja.nonemu.samurai.connection.UserMask;
import ninja.nonemu.samurai.event.EventHandler;
import ninja.nonemu.samurai.event.Priority;
import org.apache.logging.log4j.Logger;
......@@ -22,9 +23,9 @@ import org.apache.logging.log4j.Logger;
public class CommandSystemImpl implements CommandSystem {
private final Logger logger;
private final BotImpl bot;
private final Set<String> oplist;
private final Set<String> whitelist;
private final Set<String> blacklist;
private final Set<UserMask> oplist;
private final Set<UserMask> whitelist;
private final Set<UserMask> blacklist;
private final Map<String, CommandInfo> infoMap;
private final Map<String, CommandExecutor> executorMap;
private final Queue<Runnable> executionQueue;
......@@ -34,9 +35,9 @@ public class CommandSystemImpl implements CommandSystem {
public CommandSystemImpl(BotImpl bot) {
logger = bot.getLogger();
this.bot = bot;
oplist = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
whitelist = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
blacklist = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
oplist = new TreeSet<>();
whitelist = new TreeSet<>();
blacklist = new TreeSet<>();
infoMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
executorMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
executionQueue = new LinkedList<>();
......@@ -78,7 +79,7 @@ public class CommandSystemImpl implements CommandSystem {
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
while (reader.ready()) {
addOperator(reader.readLine());
addOperator(new UserMask(reader.readLine()));
}
} catch (IOException e) {
logger.error("Unable to load oplist.txt, consider fixing permissions", e);
......@@ -96,7 +97,7 @@ public class CommandSystemImpl implements CommandSystem {
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
while (reader.ready()) {
addWhitelisted(reader.readLine());
addWhitelisted(new UserMask(reader.readLine()));
}
} catch (IOException e) {
logger.error("Unable to load whitelist.txt, consider fixing permissions", e);
......@@ -114,7 +115,7 @@ public class CommandSystemImpl implements CommandSystem {
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
while (reader.ready()) {
addBlacklisted(reader.readLine());
addBlacklisted(new UserMask(reader.readLine()));
}
} catch (IOException e) {
logger.error("Unable to load blacklist.txt, consider fixing permissions", e);
......@@ -246,67 +247,44 @@ public class CommandSystemImpl implements CommandSystem {
executionQueue.add(() -> runCommand(sender, label, args));
}
/**
* Determines whether the command sender is allowed to run privileged commands.
*
* @param name The name of the sender to check.
* @return true if the sender is an operator; false otherwise.
*/
@Override
public boolean isOperator(String name) {
return oplist.contains(name);
public boolean isOperator(UserMask mask) {
for (UserMask userMask : oplist) {
if (userMask.matches(mask)) {
return true;
}
}
return false;
}
/**
* Adds a sender to the operator list. Any sender with that name can run privileged commands.
*
* @param name The name to add.
*/
@Override
public void addOperator(String name) {
oplist.add(name);
public void addOperator(UserMask mask) {
oplist.add(mask);
}
/**
* Removes a sender from the operator list. If they previously had privileges, they won't anymore.
*
* @param name The name to remove.
*/
@Override
public void removeOperator(String name) {
oplist.remove(name);
public void removeOperator(UserMask mask) {
oplist.remove(mask);
}
/**
* Determines whether the command sender is allowed to run commands when the bot's whitelist is enabled.
*
* @param name The name of the sender to check.
* @return true if the send
* er is whitelisted; false otherwise.
*/
@Override
public boolean isWhitelisted(String name) {
return whitelist.contains(name);
public boolean isWhitelisted(UserMask mask) {
for (UserMask userMask : whitelist) {
if (userMask.matches(mask)) {
return true;
}
}
return false;
}
/**
* Adds a sender to the whitelist. Any sender with that name can run commands when whitelist is enabled.
*
* @param name The name to add.
*/
@Override
public void addWhitelisted(String name) {
whitelist.add(name);
public void addWhitelisted(UserMask mask) {
whitelist.add(mask);
}
/**
* Removes a sender from the whitelist. If they previously had privileges, they won't anymore.
*
* @param name The name to remove.
*/
@Override
public void removeWhitelisted(String name) {
whitelist.remove(name);
public void removeWhitelisted(UserMask mask) {
whitelist.remove(mask);
}
@Override
......@@ -319,34 +297,23 @@ public class CommandSystemImpl implements CommandSystem {
bot.setProperty("enableWhitelist", Boolean.toString(enabled));
}
/**
* Determines whether the command sender is banned from using commands.
*
* @param name The name of the sender to check.
* @return true if the sender is blacklisted; false otherwise.
*/
@Override
public boolean isBlacklisted(String name) {
return blacklist.contains(name);
public boolean isBlacklisted(UserMask mask) {
for (UserMask userMask : blacklist) {
if (userMask.matches(mask)) {
return true;
}
}
return false;
}
/**
* Adds a sender to the blacklist. Any sender with that name cannot run commands at all.
*
* @param name The name to add.
*/
@Override
public void addBlacklisted(String name) {
blacklist.add(name);
public void addBlacklisted(UserMask mask) {
blacklist.add(mask);
}
/**
* Removes a sender from the blacklist. If they previosuly didn't have privileges, they will now.
*
* @param name The name to remove.
*/
@Override
public void removeBlacklisted(String name) {
blacklist.remove(name);
public void removeBlacklisted(UserMask mask) {
blacklist.remove(mask);
}
}
......@@ -242,8 +242,13 @@ public class ConnectionManagerImpl implements ConnectionManager {
}
@Override
public User getUser(String userId) {
return new UserImpl(bot, userId);
public User getUser(String mask) {
return new UserImpl(bot, mask);
}
@Override
public User getUser(UserMask userMask) {
return new UserImpl(bot, userMask);
}
@Override
......
package ninja.nonemu.samurai.connection;
import java.io.IOException;
import ninja.nonemu.samurai.BotImpl;
public class UserImpl implements User {
private final BotImpl bot;
private final String name;
private final UserMask mask;
public UserImpl(BotImpl bot, String name) {
public UserImpl(BotImpl bot, UserMask mask) {
this.bot = bot;
this.name = name;
this.mask = mask;
if (mask.isWildcard()) {
throw new IllegalArgumentException("Wildcard masks can't be used for users.");
}
}
public UserImpl(BotImpl bot, String mask) {
this(bot, new UserMask(mask));
}
/**
......@@ -20,7 +26,7 @@ public class UserImpl implements User {
*/
@Override
public boolean isOperator() {
return bot.getCommandSystem().isOperator(name);
return bot.getCommandSystem().isOperator(mask);
}
/**
......@@ -30,7 +36,7 @@ public class UserImpl implements User {
*/
@Override
public boolean isWhitelisted() {
return bot.getCommandSystem().isWhitelisted(name);
return bot.getCommandSystem().isWhitelisted(mask);
}
/**
......@@ -40,22 +46,32 @@ public class UserImpl implements User {
*/
@Override
public boolean isBlacklisted() {
return bot.getCommandSystem().isBlacklisted(name);
return bot.getCommandSystem().isBlacklisted(mask);
}
@Override
public UserMask getMask() {
return mask;
}
@Override
public String getNickname() {
return mask.getNickname();
}
@Override
public String getName() {
return name;
public String getUsername() {
return mask.getUsername();
}
@Override
public ninja.nonemu.irc.User moreInfo() throws IOException {
return bot.getConnectionManager().getConnection().getUser(name);
public String getHostname() {
return mask.getHostname();
}
@Override
public void sendChat(String message) {
bot.getConnectionManager().sendChat(name, message);
bot.getConnectionManager().sendChat(getNickname(), message);
}
@Override
......@@ -65,16 +81,16 @@ public class UserImpl implements User {
User user = (User) o;
return name.equals(user.getName());
return mask.equals(user.getMask());
}
@Override
public int hashCode() {
return name.hashCode();
return mask.hashCode();
}
@Override
public String toString() {
return name;
return mask.toString();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment