Merge remote-tracking branch 'origin/master'

This commit is contained in:
DNx5 2015-12-07 19:58:19 +07:00
commit a91ad46659
62 changed files with 1654 additions and 812 deletions

View File

@ -5,6 +5,8 @@
<value> <value>
<option name="AUTODETECT_INDENTS" value="false" /> <option name="AUTODETECT_INDENTS" value="false" />
<option name="LINE_SEPARATOR" value="&#10;" /> <option name="LINE_SEPARATOR" value="&#10;" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" /> <option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
<option name="JD_ADD_BLANK_AFTER_RETURN" value="true" /> <option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
<XML> <XML>

View File

@ -10,6 +10,7 @@ import fr.xephi.authme.cache.backup.JsonCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.command.CommandHandler; import fr.xephi.authme.command.CommandHandler;
import fr.xephi.authme.command.CommandInitializer;
import fr.xephi.authme.converter.Converter; import fr.xephi.authme.converter.Converter;
import fr.xephi.authme.converter.ForceFlatToSqlite; import fr.xephi.authme.converter.ForceFlatToSqlite;
import fr.xephi.authme.datasource.*; import fr.xephi.authme.datasource.*;
@ -433,7 +434,7 @@ public class AuthMe extends JavaPlugin {
* Set up the command handler. * Set up the command handler.
*/ */
private void setupCommandHandler() { private void setupCommandHandler() {
this.commandHandler = new CommandHandler(); this.commandHandler = new CommandHandler(CommandInitializer.getBaseCommands());
} }
/** /**
@ -956,14 +957,14 @@ public class AuthMe extends JavaPlugin {
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, public boolean onCommand(CommandSender sender, Command cmd,
String commandLabel, String[] args) { String commandLabel, String[] args) {
// Get the command handler, and make sure it's valid // Make sure the command handler has been initialized
if (commandHandler == null) { if (commandHandler == null) {
wrapper.getLogger().warning("AuthMe command handler is not available"); wrapper.getLogger().severe("AuthMe command handler is not available");
return false; return false;
} }
// Handle the command, return the result // Handle the command
return commandHandler.onCommand(sender, cmd, commandLabel, args); return commandHandler.processCommand(sender, commandLabel, args);
} }
/** /**

View File

@ -2,7 +2,6 @@ package fr.xephi.authme;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Wrapper; import fr.xephi.authme.util.Wrapper;
import java.io.IOException; import java.io.IOException;
@ -17,8 +16,10 @@ import java.util.Date;
*/ */
public final class ConsoleLogger { public final class ConsoleLogger {
private static final String NEW_LINE = System.getProperty("line.separator");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private static Wrapper wrapper = Wrapper.getInstance(); private static Wrapper wrapper = Wrapper.getInstance();
private static final DateFormat df = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private ConsoleLogger() { private ConsoleLogger() {
// Service class // Service class
@ -57,11 +58,11 @@ public final class ConsoleLogger {
*/ */
private static void writeLog(String message) { private static void writeLog(String message) {
String dateTime; String dateTime;
synchronized (df) { synchronized (DATE_FORMAT) {
dateTime = df.format(new Date()); dateTime = DATE_FORMAT.format(new Date());
} }
try { try {
Files.write(Settings.LOG_FILE.toPath(), (dateTime + ": " + message + StringUtils.newline).getBytes(), Files.write(Settings.LOG_FILE.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(),
StandardOpenOption.APPEND, StandardOpenOption.APPEND,
StandardOpenOption.CREATE); StandardOpenOption.CREATE);
} catch (IOException ignored) { } catch (IOException ignored) {
@ -77,6 +78,6 @@ public final class ConsoleLogger {
if (!Settings.useLogging) { if (!Settings.useLogging) {
return; return;
} }
writeLog("" + Throwables.getStackTraceAsString(ex)); writeLog(Throwables.getStackTraceAsString(ex));
} }
} }

View File

@ -5,8 +5,6 @@ package fr.xephi.authme.command;
*/ */
public class CommandArgumentDescription { public class CommandArgumentDescription {
// TODO: Allow argument to consist of infinite parts. <label ...>
/** /**
* Argument label (one-word description of the argument). * Argument label (one-word description of the argument).
*/ */

View File

@ -1,6 +1,8 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -25,7 +27,7 @@ public class CommandDescription {
* Defines the labels to execute the command. For example, if labels are "register" and "r" and the parent is * Defines the labels to execute the command. For example, if labels are "register" and "r" and the parent is
* the command for "/authme", then both "/authme register" and "/authme r" will be handled by this command. * the command for "/authme", then both "/authme register" and "/authme r" will be handled by this command.
*/ */
private List<String> labels = new ArrayList<>(); // TODO remove field initialization private List<String> labels;
/** /**
* Command description. * Command description.
*/ */
@ -49,11 +51,7 @@ public class CommandDescription {
/** /**
* The arguments the command takes. * The arguments the command takes.
*/ */
private List<CommandArgumentDescription> arguments = new ArrayList<>(); // TODO remove field initialization private List<CommandArgumentDescription> arguments;
/**
* Defines whether there is an argument maximum or not.
*/
private boolean noArgumentMaximum = false; // TODO remove field initialization
/** /**
* Defines the command permissions. * Defines the command permissions.
*/ */
@ -70,57 +68,54 @@ public class CommandDescription {
*/ */
@Deprecated @Deprecated
public CommandDescription(ExecutableCommand executableCommand, List<String> labels, String description, String detailedDescription, CommandDescription parent) { public CommandDescription(ExecutableCommand executableCommand, List<String> labels, String description, String detailedDescription, CommandDescription parent) {
this(executableCommand, labels, description, detailedDescription, parent,
new ArrayList<CommandArgumentDescription>());
}
/**
* Constructor.
*
* @param executableCommand The executable command, or null.
* @param labels List of command labels.
* @param description Command description.
* @param detailedDescription Detailed comment description.
* @param parent Parent command.
* @param arguments Command arguments.
*/
@Deprecated
public CommandDescription(ExecutableCommand executableCommand, List<String> labels, String description, String detailedDescription, CommandDescription parent, List<CommandArgumentDescription> arguments) {
setExecutableCommand(executableCommand); setExecutableCommand(executableCommand);
this.labels = labels; this.labels = labels;
this.description = description; this.description = description;
this.detailedDescription = detailedDescription; this.detailedDescription = detailedDescription;
setParent(parent); setParent(parent);
this.arguments = arguments; this.arguments = new ArrayList<>();
} }
/** /**
* Private constructor. Use {@link CommandDescription#builder()} to create instances of this class. * Private constructor. Use {@link CommandDescription#builder()} to create instances of this class.
* <p />
* Note for developers: Instances should be created with {@link CommandDescription#createInstance} to be properly
* registered in the command tree.
*/
private CommandDescription() {
}
/**
* Create an instance for internal use.
* *
* @param executableCommand The executable command, or null.
* @param labels List of command labels. * @param labels List of command labels.
* @param description Command description. * @param description Command description.
* @param detailedDescription Detailed comment description. * @param detailedDescription Detailed comment description.
* @param executableCommand The executable command, or null.
* @param parent Parent command. * @param parent Parent command.
* @param arguments Command arguments. * @param arguments Command arguments.
* @param permissions The permissions required to execute this command.
*
* @return The created instance
* @see CommandDescription#builder()
*/ */
private CommandDescription(List<String> labels, String description, String detailedDescription, private static CommandDescription createInstance(List<String> labels, String description,
ExecutableCommand executableCommand, CommandDescription parent, String detailedDescription, ExecutableCommand executableCommand,
List<CommandArgumentDescription> arguments, boolean noArgumentMaximum, CommandDescription parent, List<CommandArgumentDescription> arguments,
CommandPermissions permissions) { CommandPermissions permissions) {
this.labels = labels; CommandDescription instance = new CommandDescription();
this.description = description; instance.labels = labels;
this.detailedDescription = detailedDescription; instance.description = description;
this.executableCommand = executableCommand; instance.detailedDescription = detailedDescription;
this.parent = parent; instance.executableCommand = executableCommand;
this.arguments = arguments; instance.parent = parent;
this.noArgumentMaximum = noArgumentMaximum; instance.arguments = arguments;
this.permissions = permissions; instance.permissions = permissions;
if (parent != null) { if (parent != null) {
// Passing `this` in constructor is not very nice; consider creating a "static create()" method instead parent.addChild(instance);
parent.addChild(this);
} }
return instance;
} }
/** /**
@ -191,10 +186,6 @@ public class CommandDescription {
* @return True if the command reference is suitable to this command label, false otherwise. * @return True if the command reference is suitable to this command label, false otherwise.
*/ */
public boolean isSuitableLabel(CommandParts commandReference) { public boolean isSuitableLabel(CommandParts commandReference) {
// Make sure the command reference is valid
if (commandReference.getCount() <= 0)
return false;
// Get the parent count // Get the parent count
//getParent() = getParent().getParentCount() + 1 //getParent() = getParent().getParentCount() + 1
String element = commandReference.get(getParentCount()); String element = commandReference.get(getParentCount());
@ -220,8 +211,9 @@ public class CommandDescription {
List<String> referenceList = new ArrayList<>(); List<String> referenceList = new ArrayList<>();
// Check whether this command has a parent, if so, add the absolute parent command // Check whether this command has a parent, if so, add the absolute parent command
if (getParent() != null) if (getParent() != null) {
referenceList.addAll(getParent().getCommandReference(reference).getList()); referenceList.addAll(getParent().getCommandReference(reference).getList());
}
// Get the current label // Get the current label
referenceList.add(getLabel(reference)); referenceList.add(getLabel(reference));
@ -258,7 +250,8 @@ public class CommandDescription {
CommandParts reference = getCommandReference(other); CommandParts reference = getCommandReference(other);
// Compare the two references, return the result // Compare the two references, return the result
return reference.getDifference(new CommandParts(other.getRange(0, reference.getCount())), fullCompare); return CommandUtils.getDifference(reference.getList(),
CollectionUtils.getRange(other.getList(), 0, reference.getList().size()), fullCompare);
} }
/** /**
@ -279,15 +272,6 @@ public class CommandDescription {
this.executableCommand = executableCommand; this.executableCommand = executableCommand;
} }
/**
* Check whether this command is executable, based on the assigned executable command.
*
* @return True if this command is executable.
*/
public boolean isExecutable() {
return this.executableCommand != null;
}
/** /**
* Execute the command, if possible. * Execute the command, if possible.
* *
@ -298,10 +282,6 @@ public class CommandDescription {
* @return True on success, false on failure. * @return True on success, false on failure.
*/ */
public boolean execute(CommandSender sender, CommandParts commandReference, CommandParts commandArguments) { public boolean execute(CommandSender sender, CommandParts commandReference, CommandParts commandArguments) {
// Make sure the command is executable
if (!isExecutable())
return false;
// Execute the command, return the result // Execute the command, return the result
return getExecutableCommand().executeCommand(sender, commandReference, commandArguments); return getExecutableCommand().executeCommand(sender, commandReference, commandArguments);
} }
@ -453,10 +433,6 @@ public class CommandDescription {
return !getArguments().isEmpty(); return !getArguments().isEmpty();
} }
public boolean hasMaximumArguments() {
return !noArgumentMaximum; // TODO ljacqu 20151130 Change variable name
}
/** /**
* Get the command description. * Get the command description.
* *
@ -492,13 +468,13 @@ public class CommandDescription {
return new FoundCommandResult( return new FoundCommandResult(
this, this,
getCommandReference(queryReference), getCommandReference(queryReference),
new CommandParts(), new CommandParts(new ArrayList<String>()),
queryReference); queryReference);
} }
// Get the new command reference and arguments // Get the new command reference and arguments
CommandParts newReference = new CommandParts(queryReference.getRange(0, getParentCount() + 1)); CommandParts newReference = new CommandParts(CollectionUtils.getRange(queryReference.getList(), 0, getParentCount() + 1));
CommandParts newArguments = new CommandParts(queryReference.getRange(getParentCount() + 1)); CommandParts newArguments = new CommandParts(CollectionUtils.getRange(queryReference.getList(), getParentCount() + 1));
// Handle the child's, if this command has any // Handle the child's, if this command has any
if (getChildren().size() > 0) { if (getChildren().size() > 0) {
@ -580,16 +556,6 @@ public class CommandDescription {
return this.permissions; return this.permissions;
} }
/**
* Set the command permissions.
*
* @param permissionNode The permission node required.
* @param defaultPermission The default permission.
*/
public void setCommandPermissions(PermissionNode permissionNode, CommandPermissions.DefaultPermission defaultPermission) {
this.permissions = new CommandPermissions(permissionNode, defaultPermission);
}
public static CommandBuilder builder() { public static CommandBuilder builder() {
return new CommandBuilder(); return new CommandBuilder();
} }
@ -604,7 +570,6 @@ public class CommandDescription {
private ExecutableCommand executableCommand; private ExecutableCommand executableCommand;
private CommandDescription parent; private CommandDescription parent;
private List<CommandArgumentDescription> arguments = new ArrayList<>(); private List<CommandArgumentDescription> arguments = new ArrayList<>();
private boolean noArgumentMaximum;
private CommandPermissions permissions; private CommandPermissions permissions;
/** /**
@ -614,14 +579,13 @@ public class CommandDescription {
* @return The generated CommandDescription object * @return The generated CommandDescription object
*/ */
public CommandDescription build() { public CommandDescription build() {
return new CommandDescription( return createInstance(
getOrThrow(labels, "labels"), getOrThrow(labels, "labels"),
firstNonNull(description, ""), firstNonNull(description, ""),
firstNonNull(detailedDescription, ""), firstNonNull(detailedDescription, ""),
getOrThrow(executableCommand, "executableCommand"), getOrThrow(executableCommand, "executableCommand"),
firstNonNull(parent, null), firstNonNull(parent, null),
arguments, arguments,
noArgumentMaximum,
firstNonNull(permissions, null) firstNonNull(permissions, null)
); );
} }
@ -670,12 +634,7 @@ public class CommandDescription {
return this; return this;
} }
public CommandBuilder noArgumentMaximum(boolean noArgumentMaximum) { public CommandBuilder permissions(DefaultPermission defaultPermission,
this.noArgumentMaximum = noArgumentMaximum;
return this;
}
public CommandBuilder permissions(CommandPermissions.DefaultPermission defaultPermission,
PermissionNode... permissionNodes) { PermissionNode... permissionNodes) {
this.permissions = new CommandPermissions(asMutableList(permissionNodes), defaultPermission); this.permissions = new CommandPermissions(asMutableList(permissionNodes), defaultPermission);
return this; return this;

View File

@ -2,13 +2,14 @@ package fr.xephi.authme.command;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription} * The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription}
@ -28,104 +29,70 @@ public class CommandHandler {
*/ */
private static final double SUGGEST_COMMAND_THRESHOLD = 0.75; private static final double SUGGEST_COMMAND_THRESHOLD = 0.75;
private final Set<CommandDescription> commands;
/** /**
* Process a command. * Create a command handler.
*
* @param commands The collection of available AuthMe commands
*/
public CommandHandler(Set<CommandDescription> commands) {
this.commands = commands;
}
/**
* Map a command that was invoked to the proper {@link CommandDescription} or return a useful error
* message upon failure.
* *
* @param sender The command sender (Bukkit). * @param sender The command sender (Bukkit).
* @param bukkitCommand The command (Bukkit).
* @param bukkitCommandLabel The command label (Bukkit). * @param bukkitCommandLabel The command label (Bukkit).
* @param bukkitArgs The command arguments (Bukkit). * @param bukkitArgs The command arguments (Bukkit).
* *
* @return True if the command was executed, false otherwise. * @return True if the command was executed, false otherwise.
*/ */
// TODO ljacqu 20151129: Rename onCommand() method to something not suggesting it is auto-invoked by an event public boolean processCommand(CommandSender sender, String bukkitCommandLabel, String[] bukkitArgs) {
public boolean onCommand(CommandSender sender, Command bukkitCommand, String bukkitCommandLabel, String[] bukkitArgs) {
List<String> commandArgs = skipEmptyArguments(bukkitArgs); List<String> commandArgs = skipEmptyArguments(bukkitArgs);
// Add the Bukkit command label to the front so we get a list like [authme, register, pass, passConfirm]
commandArgs.add(0, bukkitCommandLabel);
// Make sure the command isn't empty (does this happen?) // TODO: remove commandParts
CommandParts commandReference = new CommandParts(bukkitCommandLabel, commandArgs); CommandParts commandReference = new CommandParts(commandArgs);
if (commandReference.getCount() == 0)
return false;
// Get a suitable command for this reference, and make sure it isn't null // Get a suitable command for this reference, and make sure it isn't null
FoundCommandResult result = findCommand(commandReference); FoundCommandResult result = findCommand(commandReference);
if (result == null) { if (result == null) {
// TODO ljacqu 20151204: Log more information to the console (bukkitCommandLabel)
sender.sendMessage(ChatColor.DARK_RED + "Failed to parse " + AuthMe.getPluginName() + " command!"); sender.sendMessage(ChatColor.DARK_RED + "Failed to parse " + AuthMe.getPluginName() + " command!");
return false; return false;
} }
// Get the base command
String baseCommand = commandReference.get(0); String baseCommand = commandArgs.get(0);
// Make sure the difference between the command reference and the actual command isn't too big // Make sure the difference between the command reference and the actual command isn't too big
final double commandDifference = result.getDifference(); final double commandDifference = result.getDifference();
if (commandDifference > ASSUME_COMMAND_THRESHOLD) { if (commandDifference <= ASSUME_COMMAND_THRESHOLD) {
// Show the unknown command warning
sender.sendMessage(ChatColor.DARK_RED + "Unknown command!");
// Show a command suggestion if available and the difference isn't too big
if (commandDifference < SUGGEST_COMMAND_THRESHOLD)
if (result.getCommandDescription() != null)
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD + "/" + result.getCommandDescription().getCommandReference(commandReference) + ChatColor.YELLOW + "?");
// Show the help command
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + baseCommand + " help" + ChatColor.YELLOW + " to view help.");
return true;
}
// Show a message when the command handler is assuming a command // Show a message when the command handler is assuming a command
if (commandDifference > 0) { if (commandDifference > 0) {
// Get the suggested command sendCommandAssumptionMessage(sender, result, commandReference);
CommandParts suggestedCommandParts = new CommandParts(result.getCommandDescription().getCommandReference(commandReference));
// Show the suggested command
sender.sendMessage(ChatColor.DARK_RED + "Unknown command, assuming " + ChatColor.GOLD + "/" + suggestedCommandParts +
ChatColor.DARK_RED + "!");
} }
// Make sure the command is executable
if (!result.isExecutable()) {
// Get the command reference
CommandParts helpCommandReference = new CommandParts(result.getCommandReference().getRange(1));
// Show the unknown command warning
sender.sendMessage(ChatColor.DARK_RED + "Invalid command!");
// Show the help command
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + baseCommand + " help " + helpCommandReference + ChatColor.YELLOW + " to view help.");
return true;
}
// Make sure the command sender has permission
if (!result.hasPermission(sender)) { if (!result.hasPermission(sender)) {
// Show the no permissions warning
sender.sendMessage(ChatColor.DARK_RED + "You don't have permission to use this command!"); sender.sendMessage(ChatColor.DARK_RED + "You don't have permission to use this command!");
return true; } else if (!result.hasProperArguments()) {
} sendImproperArgumentsMessage(sender, result, commandReference, baseCommand);
} else {
// Make sure the command sender has permission
if (!result.hasProperArguments()) {
// Get the command and the suggested command reference
CommandParts suggestedCommandReference = new CommandParts(result.getCommandDescription().getCommandReference(commandReference));
CommandParts helpCommandReference = new CommandParts(suggestedCommandReference.getRange(1));
// Show the invalid arguments warning
sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!");
// Show the command argument help
HelpProvider.showHelp(sender, commandReference, suggestedCommandReference, true, false, true, false, false, false);
// Show the command to use for detailed help
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/" + baseCommand + " help " + helpCommandReference);
return true;
}
// Execute the command if it's suitable
return result.executeCommand(sender); return result.executeCommand(sender);
} }
} else {
sendUnknownCommandMessage(sender, commandDifference, result, baseCommand);
}
return true;
}
/** /**
* Skips all entries of the given array that are simply whitespace. * Skip all entries of the given array that are simply whitespace.
* *
* @param args The array to process * @param args The array to process
* @return List of the items that are not empty * @return List of the items that are not empty
@ -162,10 +129,7 @@ public class CommandHandler {
if (queryReference.getCount() <= 0) if (queryReference.getCount() <= 0)
return null; return null;
// TODO ljacqu 20151129: If base commands are only used in here (or in the future CommandHandler after changes), for (CommandDescription commandDescription : commands) {
// it might make sense to make the CommandInitializer package-private and to return its result into this class
// instead of regularly fetching the list of base commands from the other class.
for (CommandDescription commandDescription : CommandInitializer.getBaseCommands()) {
// Check whether there's a command description available for the // Check whether there's a command description available for the
// current command // current command
if (!commandDescription.isSuitableLabel(queryReference)) if (!commandDescription.isSuitableLabel(queryReference))
@ -186,7 +150,7 @@ public class CommandHandler {
* *
* @return The command found, or null. * @return The command found, or null.
*/ */
public CommandDescription findCommand(List<String> commandParts) { private CommandDescription findCommand(List<String> commandParts) {
// Make sure the command reference is valid // Make sure the command reference is valid
if (commandParts.isEmpty()) { if (commandParts.isEmpty()) {
return null; return null;
@ -211,10 +175,63 @@ public class CommandHandler {
return null; return null;
} }
for (CommandDescription command : commands) { for (CommandDescription command : commands) {
if (command.getLabels().contains(label)) { if (command.getLabels().contains(label)) { // TODO ljacqu should be case-insensitive
return command; return command;
} }
} }
return null; return null;
} }
/**
* Show an "unknown command" to the user and suggests an existing command if its similarity is within
* the defined threshold.
*
* @param sender The command sender
* @param commandDifference The difference between the invoked command and the existing one
* @param result The command that was found during the mapping process
* @param baseCommand The base command (TODO: This is probably already in FoundCommandResult)
*/
private static void sendUnknownCommandMessage(CommandSender sender, double commandDifference,
FoundCommandResult result, String baseCommand) {
CommandParts commandReference = result.getCommandReference();
sender.sendMessage(ChatColor.DARK_RED + "Unknown command!");
// Show a command suggestion if available and the difference isn't too big
if (commandDifference < SUGGEST_COMMAND_THRESHOLD && result.getCommandDescription() != null) {
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD + "/"
+ result.getCommandDescription().getCommandReference(commandReference) + ChatColor.YELLOW + "?");
}
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + baseCommand + " help"
+ ChatColor.YELLOW + " to view help.");
}
private static void sendImproperArgumentsMessage(CommandSender sender, FoundCommandResult result,
CommandParts commandReference, String baseCommand) {
// Get the command and the suggested command reference
List<String> suggestedCommandReference =
result.getCommandDescription().getCommandReference(commandReference).getList();
List<String> helpCommandReference = CollectionUtils.getRange(suggestedCommandReference, 1);
// Show the invalid arguments warning
sender.sendMessage(ChatColor.DARK_RED + "Incorrect command arguments!");
// Show the command argument help
HelpProvider.showHelp(sender, commandReference, new CommandParts(suggestedCommandReference),
true, false, true, false, false, false);
// Show the command to use for detailed help
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/" + baseCommand
+ " help " + CommandUtils.labelsToString(helpCommandReference));
}
private static void sendCommandAssumptionMessage(CommandSender sender, FoundCommandResult result,
CommandParts commandReference) {
List<String> assumedCommandParts =
result.getCommandDescription().getCommandReference(commandReference).getList();
sender.sendMessage(ChatColor.DARK_RED + "Unknown command, assuming " + ChatColor.GOLD + "/"
+ CommandUtils.labelsToString(assumedCommandParts) + ChatColor.DARK_RED + "!");
}
} }

View File

@ -3,7 +3,7 @@ package fr.xephi.authme.command;
import fr.xephi.authme.command.executable.HelpCommand; import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.command.executable.authme.AccountsCommand; import fr.xephi.authme.command.executable.authme.AccountsCommand;
import fr.xephi.authme.command.executable.authme.AuthMeCommand; import fr.xephi.authme.command.executable.authme.AuthMeCommand;
import fr.xephi.authme.command.executable.authme.ChangePasswordCommand; import fr.xephi.authme.command.executable.authme.ChangePasswordAdminCommand;
import fr.xephi.authme.command.executable.authme.FirstSpawnCommand; import fr.xephi.authme.command.executable.authme.FirstSpawnCommand;
import fr.xephi.authme.command.executable.authme.ForceLoginCommand; import fr.xephi.authme.command.executable.authme.ForceLoginCommand;
import fr.xephi.authme.command.executable.authme.GetEmailCommand; import fr.xephi.authme.command.executable.authme.GetEmailCommand;
@ -12,45 +12,46 @@ import fr.xephi.authme.command.executable.authme.LastLoginCommand;
import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand; import fr.xephi.authme.command.executable.authme.PurgeBannedPlayersCommand;
import fr.xephi.authme.command.executable.authme.PurgeCommand; import fr.xephi.authme.command.executable.authme.PurgeCommand;
import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand; import fr.xephi.authme.command.executable.authme.PurgeLastPositionCommand;
import fr.xephi.authme.command.executable.authme.RegisterCommand; import fr.xephi.authme.command.executable.authme.RegisterAdminCommand;
import fr.xephi.authme.command.executable.authme.ReloadCommand; import fr.xephi.authme.command.executable.authme.ReloadCommand;
import fr.xephi.authme.command.executable.authme.SetEmailCommand; import fr.xephi.authme.command.executable.authme.SetEmailCommand;
import fr.xephi.authme.command.executable.authme.SetFirstSpawnCommand; import fr.xephi.authme.command.executable.authme.SetFirstSpawnCommand;
import fr.xephi.authme.command.executable.authme.SetSpawnCommand; import fr.xephi.authme.command.executable.authme.SetSpawnCommand;
import fr.xephi.authme.command.executable.authme.SpawnCommand; import fr.xephi.authme.command.executable.authme.SpawnCommand;
import fr.xephi.authme.command.executable.authme.SwitchAntiBotCommand; import fr.xephi.authme.command.executable.authme.SwitchAntiBotCommand;
import fr.xephi.authme.command.executable.authme.UnregisterCommand; import fr.xephi.authme.command.executable.authme.UnregisterAdminCommand;
import fr.xephi.authme.command.executable.authme.VersionCommand; import fr.xephi.authme.command.executable.authme.VersionCommand;
import fr.xephi.authme.command.executable.captcha.CaptchaCommand; import fr.xephi.authme.command.executable.captcha.CaptchaCommand;
import fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand;
import fr.xephi.authme.command.executable.converter.ConverterCommand; import fr.xephi.authme.command.executable.converter.ConverterCommand;
import fr.xephi.authme.command.executable.email.AddEmailCommand; import fr.xephi.authme.command.executable.email.AddEmailCommand;
import fr.xephi.authme.command.executable.email.ChangeEmailCommand; import fr.xephi.authme.command.executable.email.ChangeEmailCommand;
import fr.xephi.authme.command.executable.email.RecoverEmailCommand; import fr.xephi.authme.command.executable.email.RecoverEmailCommand;
import fr.xephi.authme.command.executable.login.LoginCommand; import fr.xephi.authme.command.executable.login.LoginCommand;
import fr.xephi.authme.command.executable.logout.LogoutCommand; import fr.xephi.authme.command.executable.logout.LogoutCommand;
import fr.xephi.authme.command.executable.register.RegisterCommand;
import fr.xephi.authme.command.executable.unregister.UnregisterCommand;
import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.util.Wrapper; import fr.xephi.authme.util.Wrapper;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import static fr.xephi.authme.command.CommandPermissions.DefaultPermission.ALLOWED; import static fr.xephi.authme.permission.DefaultPermission.ALLOWED;
import static fr.xephi.authme.command.CommandPermissions.DefaultPermission.OP_ONLY; import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
/** /**
* Initializes all available AuthMe commands. * Initializes all available AuthMe commands.
*/ */
public final class CommandInitializer { public final class CommandInitializer {
private static List<CommandDescription> baseCommands; private static Set<CommandDescription> baseCommands;
private CommandInitializer() { private CommandInitializer() {
// Helper class // Helper class
} }
public static List<CommandDescription> getBaseCommands() { public static Set<CommandDescription> getBaseCommands() {
if (baseCommands == null) { if (baseCommands == null) {
Wrapper.getInstance().getLogger().info("Initializing AuthMe commands"); Wrapper.getInstance().getLogger().info("Initializing AuthMe commands");
initializeCommands(); initializeCommands();
@ -89,8 +90,8 @@ public final class CommandInitializer {
.detailedDescription("Register the specified player with the specified password.") .detailedDescription("Register the specified player with the specified password.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.withArgument("password", "Password", false) .withArgument("password", "Password", false)
.permissions(OP_ONLY, PlayerPermission.REGISTER) .permissions(OP_ONLY, AdminPermission.REGISTER)
.executableCommand(new RegisterCommand()) .executableCommand(new RegisterAdminCommand())
.build(); .build();
// Register the unregister command // Register the unregister command
@ -100,8 +101,8 @@ public final class CommandInitializer {
.description("Unregister a player") .description("Unregister a player")
.detailedDescription("Unregister the specified player.") .detailedDescription("Unregister the specified player.")
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.permissions(OP_ONLY, PlayerPermission.UNREGISTER) .permissions(OP_ONLY, AdminPermission.UNREGISTER)
.executableCommand(new UnregisterCommand()) .executableCommand(new UnregisterAdminCommand())
.build(); .build();
// Register the forcelogin command // Register the forcelogin command
@ -124,7 +125,7 @@ public final class CommandInitializer {
.withArgument("player", "Player name", false) .withArgument("player", "Player name", false)
.withArgument("pwd", "New password", false) .withArgument("pwd", "New password", false)
.permissions(OP_ONLY, AdminPermission.CHANGE_PASSWORD) .permissions(OP_ONLY, AdminPermission.CHANGE_PASSWORD)
.executableCommand(new ChangePasswordCommand()) .executableCommand(new ChangePasswordAdminCommand())
.build(); .build();
// Register the last login command // Register the last login command
@ -161,7 +162,7 @@ public final class CommandInitializer {
.build(); .build();
// Register the setemail command // Register the setemail command
CommandDescription setEmailCommand = CommandDescription.builder() CommandDescription.builder()
.executableCommand(new SetEmailCommand()) .executableCommand(new SetEmailCommand())
.parent(AUTHME_BASE) .parent(AUTHME_BASE)
.labels("chgemail", "chgmail", "setemail", "setmail") .labels("chgemail", "chgmail", "setemail", "setmail")
@ -173,96 +174,101 @@ public final class CommandInitializer {
.build(); .build();
// Register the getip command // Register the getip command
CommandDescription getIpCommand = new CommandDescription(new GetIpCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new GetIpCommand())
add("getip"); .parent(AUTHME_BASE)
add("ip"); .labels("getip", "ip")
} .description("Get player's IP")
}, "Get player's IP", "Get the IP address of the specified online player.", AUTHME_BASE); .detailedDescription("Get the IP address of the specified online player.")
getIpCommand.setCommandPermissions(AdminPermission.GET_IP, OP_ONLY); .permissions(OP_ONLY, AdminPermission.GET_IP)
getIpCommand.addArgument(new CommandArgumentDescription("player", "Online player name", true)); .withArgument("player", "Player Name", false)
.build();
// Register the spawn command // Register the spawn command
CommandDescription spawnCommand = new CommandDescription(new SpawnCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new SpawnCommand())
add("spawn"); .parent(AUTHME_BASE)
add("home"); .labels("spawn", "home")
} .description("Teleport to spawn")
}, "Teleport to spawn", "Teleport to the spawn.", AUTHME_BASE); .detailedDescription("Teleport to the spawn.")
spawnCommand.setCommandPermissions(AdminPermission.SPAWN, OP_ONLY); .permissions(OP_ONLY, AdminPermission.SPAWN)
.withArgument("player", "Player Name", false)
.build();
// Register the setspawn command // Register the setspawn command
CommandDescription setSpawnCommand = new CommandDescription(new SetSpawnCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new SetSpawnCommand())
add("setspawn"); .parent(AUTHME_BASE)
add("chgspawn"); .labels("setspawn", "chgspawn")
} .description("Change the spawn")
}, "Change the spawn", "Change the player's spawn to your current position.", AUTHME_BASE); .detailedDescription("Change the player's spawn to your current position.")
setSpawnCommand.setCommandPermissions(AdminPermission.SET_SPAWN, OP_ONLY); .permissions(OP_ONLY, AdminPermission.SET_SPAWN)
.build();
// Register the firstspawn command // Register the firstspawn command
CommandDescription firstSpawnCommand = new CommandDescription(new FirstSpawnCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new FirstSpawnCommand())
add("firstspawn"); .parent(AUTHME_BASE)
add("firsthome"); .labels("firstspawn", "firsthome")
} .description("Teleport to first spawn")
}, "Teleport to first spawn", "Teleport to the first spawn.", AUTHME_BASE); .detailedDescription("Teleport to the first spawn.")
firstSpawnCommand.setCommandPermissions(AdminPermission.FIRST_SPAWN, OP_ONLY); .permissions(OP_ONLY, AdminPermission.FIRST_SPAWN)
.build();
// Register the setfirstspawn command // Register the setfirstspawn command
CommandDescription setFirstSpawnCommand = new CommandDescription(new SetFirstSpawnCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new SetFirstSpawnCommand())
add("setfirstspawn"); .parent(AUTHME_BASE)
add("chgfirstspawn"); .labels("setfirstspawn", "chgfirstspawn")
} .description("Change the first spawn")
}, "Change the first spawn", "Change the first player's spawn to your current position.", AUTHME_BASE); .detailedDescription("Change the first player's spawn to your current position.")
setFirstSpawnCommand.setCommandPermissions(AdminPermission.SET_FIRST_SPAWN, OP_ONLY); .permissions(OP_ONLY, AdminPermission.SET_FIRST_SPAWN)
.build();
// Register the purge command // Register the purge command
CommandDescription purgeCommand = new CommandDescription(new PurgeCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new PurgeCommand())
add("purge"); .parent(AUTHME_BASE)
add("delete"); .labels("purge", "delete")
} .description("Purge old data")
}, "Purge old data", "Purge old AuthMeReloaded data longer than the specified amount of days ago.", AUTHME_BASE); .detailedDescription("Purge old AuthMeReloaded data longer than the specified amount of days ago.")
purgeCommand.setCommandPermissions(AdminPermission.PURGE, OP_ONLY); .permissions(OP_ONLY, AdminPermission.PURGE)
purgeCommand.addArgument(new CommandArgumentDescription("days", "Number of days", false)); .withArgument("days", "Number of days", false)
.build();
// Register the purgelastposition command // Register the purgelastposition command
CommandDescription purgeLastPositionCommand = new CommandDescription(new PurgeLastPositionCommand(), new ArrayList<String>() { CommandDescription.builder()
{ .executableCommand(new PurgeLastPositionCommand())
add("resetpos"); .parent(AUTHME_BASE)
add("purgelastposition"); .labels("resetpos", "purgelastposition", "purgelastpos", "resetposition", "resetlastposition", "resetlastpos")
add("purgelastpos"); .description("Purge player's last position")
add("resetposition"); .detailedDescription("Purge the last know position of the specified player.")
add("resetlastposition"); .permissions(OP_ONLY, AdminPermission.PURGE_LAST_POSITION)
add("resetlastpos"); .withArgument("player", "Player name", false)
} .build();
}, "Purge player's last position", "Purge the last know position of the specified player.", AUTHME_BASE);
purgeLastPositionCommand.setCommandPermissions(AdminPermission.PURGE_LAST_POSITION, OP_ONLY);
purgeLastPositionCommand.addArgument(new CommandArgumentDescription("player", "Player name", true));
// Register the purgebannedplayers command // Register the purgebannedplayers command
CommandDescription purgeBannedPlayersCommand = new CommandDescription(new PurgeBannedPlayersCommand(), new ArrayList<String>() { CommandDescription purgeBannedPlayersCommand = CommandDescription.builder()
{ .executableCommand(new PurgeBannedPlayersCommand())
add("purgebannedplayers"); .parent(AUTHME_BASE)
add("purgebannedplayer"); .labels("purgebannedplayers", "purgebannedplayer", "deletebannedplayers", "deletebannedplayer")
add("deletebannedplayers"); .description("Purge banned players data")
add("deletebannedplayer"); .detailedDescription("Purge all AuthMeReloaded data for banned players.")
} .permissions(OP_ONLY, AdminPermission.PURGE_BANNED_PLAYERS)
}, "Purge banned palyers data", "Purge all AuthMeReloaded data for banned players.", AUTHME_BASE); .build();
purgeBannedPlayersCommand.setCommandPermissions(AdminPermission.PURGE_BANNED_PLAYERS, OP_ONLY);
// Register the switchantibot command // Register the switchantibot command
CommandDescription switchAntiBotCommand = new CommandDescription(new SwitchAntiBotCommand(), new ArrayList<String>() { CommandDescription switchAntiBotCommand = CommandDescription.builder()
{ .executableCommand(new SwitchAntiBotCommand())
add("switchantibot"); .parent(AUTHME_BASE)
add("toggleantibot"); .labels("switchantibot", "toggleantibot", "antibot")
add("antibot"); .description("Switch AntiBot mode")
} .detailedDescription("Switch or toggle the AntiBot mode to the specified state.")
}, "Switch AntiBot mode", "Switch or toggle the AntiBot mode to the specified state.", AUTHME_BASE); .permissions(OP_ONLY, AdminPermission.SWITCH_ANTIBOT)
switchAntiBotCommand.setCommandPermissions(AdminPermission.SWITCH_ANTIBOT, OP_ONLY); .withArgument("mode", "ON / OFF", true)
switchAntiBotCommand.addArgument(new CommandArgumentDescription("mode", "ON / OFF", true)); .build();
// // Register the resetname command // // Register the resetname command
// CommandDescription resetNameCommand = new CommandDescription( // CommandDescription resetNameCommand = new CommandDescription(
@ -278,26 +284,27 @@ public final class CommandInitializer {
// CommandPermissions.DefaultPermission.OP_ONLY); // CommandPermissions.DefaultPermission.OP_ONLY);
// Register the reload command // Register the reload command
CommandDescription reloadCommand = new CommandDescription(new ReloadCommand(), new ArrayList<String>() { CommandDescription reloadCommand = CommandDescription.builder()
{ .executableCommand(new ReloadCommand())
add("reload"); .parent(AUTHME_BASE)
add("rld"); .labels("reload", "rld")
} .description("Reload plugin")
}, "Reload plugin", "Reload the AuthMeReloaded plugin.", AUTHME_BASE); .detailedDescription("Reload the AutheMeReloaded plugin.")
reloadCommand.setCommandPermissions(AdminPermission.RELOAD, OP_ONLY); .permissions(OP_ONLY, AdminPermission.RELOAD)
.build();
// Register the version command // Register the version command
CommandDescription versionCommand = CommandDescription.builder() CommandDescription.builder()
.executableCommand(new VersionCommand()) .parent(AUTHME_BASE)
.labels("version", "ver", "v", "about", "info") .labels("version", "ver", "v", "about", "info")
.description("Version info") .description("Version info")
.detailedDescription("Show detailed information about the installed AuthMeReloaded version, and shows the " .detailedDescription("Show detailed information about the installed AuthMeReloaded version, and shows the "
+ "developers, contributors, license and other information.") + "developers, contributors, license and other information.")
.parent(AUTHME_BASE) .executableCommand(new VersionCommand())
.build(); .build();
// Register the base login command // Register the base login command
CommandDescription loginBaseCommand = CommandDescription.builder() final CommandDescription LOGIN_BASE = CommandDescription.builder()
.executableCommand(new LoginCommand()) .executableCommand(new LoginCommand())
.labels("login", "l") .labels("login", "l")
.description("Login command") .description("Login command")
@ -308,159 +315,207 @@ public final class CommandInitializer {
.build(); .build();
// Register the help command // Register the help command
CommandDescription loginHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription loginHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded login commands.", loginBaseCommand); .executableCommand(helpCommandExecutable)
loginHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(LOGIN_BASE)
.labels(helpCommandLabels)
.description("View Help")
.detailedDescription("View detailed help pages about AuthMeReloaded login commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base logout command // Register the base logout command
CommandDescription logoutBaseCommand = new CommandDescription(new LogoutCommand(), new ArrayList<String>() { CommandDescription LOGOUT_BASE = CommandDescription.builder()
{ .executableCommand(new LogoutCommand())
add("logout"); .parent(null)
} .labels("logout")
}, "Logout command", "Command to logout using AuthMeReloaded.", null); .description("Logout command")
logoutBaseCommand.setCommandPermissions(PlayerPermission.LOGOUT, CommandPermissions.DefaultPermission.ALLOWED); .detailedDescription("Command to logout using AuthMeReloaded.")
.permissions(ALLOWED, PlayerPermission.LOGOUT)
.build();
// Register the help command // Register the help command
CommandDescription logoutHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription logoutHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded logout commands.", logoutBaseCommand); .executableCommand(helpCommandExecutable)
logoutHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(LOGOUT_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded logout commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base register command // Register the base register command
CommandDescription registerBaseCommand = new CommandDescription(new fr.xephi.authme.command.executable.register.RegisterCommand(), new ArrayList<String>() { final CommandDescription REGISTER_BASE = CommandDescription.builder()
{ .parent(null)
add("register"); .labels("register", "reg")
add("reg"); .description("Registration command")
} .detailedDescription("Command to register using AuthMeReloaded.")
}, "Registration command", "Command to register using AuthMeReloaded.", null); .withArgument("password", "Password", false)
registerBaseCommand.setCommandPermissions(PlayerPermission.REGISTER, CommandPermissions.DefaultPermission.ALLOWED); .withArgument("verifyPassword", "Verify password", false)
registerBaseCommand.addArgument(new CommandArgumentDescription("password", "Password", false)); .permissions(ALLOWED, PlayerPermission.REGISTER)
registerBaseCommand.addArgument(new CommandArgumentDescription("verifyPassword", "Verify password", false)); .executableCommand(new RegisterCommand())
.build();
// Register the help command // Register the help command
CommandDescription registerHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription registerHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded register commands.", registerBaseCommand); .executableCommand(helpCommandExecutable)
registerHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(REGISTER_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded register commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base unregister command // Register the base unregister command
CommandDescription unregisterBaseCommand = new CommandDescription(new fr.xephi.authme.command.executable.unregister.UnregisterCommand(), new ArrayList<String>() { CommandDescription UNREGISTER_BASE = CommandDescription.builder()
{ .executableCommand(new UnregisterCommand())
add("unregister"); .parent(null)
add("unreg"); .labels("unreg", "unregister")
} .description("Unregistration Command")
}, "Unregistration command", "Command to unregister using AuthMeReloaded.", null); .detailedDescription("Command to unregister using AuthMeReloaded.")
unregisterBaseCommand.setCommandPermissions(PlayerPermission.UNREGISTER, CommandPermissions.DefaultPermission.ALLOWED); .permissions(ALLOWED, PlayerPermission.UNREGISTER)
unregisterBaseCommand.addArgument(new CommandArgumentDescription("password", "Password", false)); .withArgument("password", "Password", false)
.build();
// Register the help command // Register the help command
CommandDescription unregisterHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, "View help", "View detailed help pages about AuthMeReloaded unregister commands.", unregisterBaseCommand); CommandDescription unregisterHelpCommand = CommandDescription.builder()
unregisterHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .executableCommand(helpCommandExecutable)
.parent(UNREGISTER_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded unregister commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base changepassword command // Register the base changepassword command
CommandDescription changePasswordBaseCommand = new CommandDescription(new fr.xephi.authme.command.executable.changepassword.ChangePasswordCommand(), new ArrayList<String>() { final CommandDescription CHANGE_PASSWORD_BASE = CommandDescription.builder()
{ .executableCommand(new ChangePasswordCommand())
add("changepassword"); .parent(null)
add("changepass"); .labels("changepassword", "changepass", "cp")
} .description("Change password Command")
}, "Change password command", "Command to change your password using AuthMeReloaded.", null); .detailedDescription("Command to change your password using AuthMeReloaded.")
changePasswordBaseCommand.setCommandPermissions(PlayerPermission.CHANGE_PASSWORD, CommandPermissions.DefaultPermission.ALLOWED); .permissions(ALLOWED, PlayerPermission.CHANGE_PASSWORD)
changePasswordBaseCommand.addArgument(new CommandArgumentDescription("password", "Password", false)); .withArgument("password", "Password", false)
changePasswordBaseCommand.addArgument(new CommandArgumentDescription("verifyPassword", "Verify password", false)); .withArgument("verifyPassword", "Verify password.", false)
.build();
// Register the help command // Register the help command
CommandDescription changePasswordHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription changePasswordHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded change password commands.", changePasswordBaseCommand); .executableCommand(helpCommandExecutable)
changePasswordHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(CHANGE_PASSWORD_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded changepassword commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base Dungeon Maze command // Register the base Email command
CommandDescription emailBaseCommand = new CommandDescription(helpCommandExecutable, new ArrayList<String>() { CommandDescription EMAIL_BASE = CommandDescription.builder()
{ .executableCommand(helpCommandExecutable)
add("email"); .parent(null)
add("mail"); .labels("email", "mail")
} .description("Email command")
}, "E-mail command", "The AuthMe Reloaded E-mail command. The root for all E-mail commands.", null); .detailedDescription("The AuthMeReloaded Email command base.")
.build();
// Register the help command // Register the help command
CommandDescription emailHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription emailHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded help commands.", emailBaseCommand); .executableCommand(helpCommandExecutable)
emailHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(EMAIL_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded email commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the add command // Register the add command
CommandDescription addEmailCommand = new CommandDescription(new AddEmailCommand(), new ArrayList<String>() { CommandDescription addEmailCommand = CommandDescription.builder()
{ .executableCommand(new AddEmailCommand())
add("add"); .parent(EMAIL_BASE)
add("addemail"); .labels("add", "addemail", "addmail")
add("addmail"); .description("Add Email")
} .detailedDescription("Add a new Email address to your account.")
}, "Add E-mail", "Add an new E-Mail address to your account.", emailBaseCommand); .permissions(ALLOWED, PlayerPermission.ADD_EMAIL)
addEmailCommand.setCommandPermissions(PlayerPermission.ADD_EMAIL, CommandPermissions.DefaultPermission.ALLOWED); .withArgument("email", "Email address", false)
addEmailCommand.addArgument(new CommandArgumentDescription("email", "Email address", false)); .withArgument("verifyEmail", "Email address verification", false)
addEmailCommand.addArgument(new CommandArgumentDescription("verifyEmail", "Email address verification", false)); .build();
// Register the change command // Register the change command
CommandDescription changeEmailCommand = new CommandDescription(new ChangeEmailCommand(), new ArrayList<String>() { CommandDescription changeEmailCommand = CommandDescription.builder()
{ .executableCommand(new ChangeEmailCommand())
add("change"); .parent(EMAIL_BASE)
add("changeemail"); .labels("change", "changeemail", "changemail")
add("changemail"); .description("Change Email")
} .detailedDescription("Change an Email address of your account.")
}, "Change E-mail", "Change an E-Mail address of your account.", emailBaseCommand); .permissions(ALLOWED, PlayerPermission.CHANGE_EMAIL)
changeEmailCommand.setCommandPermissions(PlayerPermission.CHANGE_EMAIL, CommandPermissions.DefaultPermission.ALLOWED); .withArgument("oldEmail", "Old email address", false)
changeEmailCommand.addArgument(new CommandArgumentDescription("oldEmail", "Old email address", false)); .withArgument("newEmail", "New email address", false)
changeEmailCommand.addArgument(new CommandArgumentDescription("newEmail", "New email address", false)); .build();
// Register the recover command // Register the recover command
CommandDescription recoverEmailCommand = new CommandDescription(new RecoverEmailCommand(), new ArrayList<String>() { CommandDescription recoverEmailCommand = CommandDescription.builder()
{ .executableCommand(new RecoverEmailCommand())
add("recover"); .parent(EMAIL_BASE)
add("recovery"); .labels("recover", "recovery", "recoveremail", "recovermail")
add("recoveremail"); .description("Recover password using Email")
add("recovermail"); .detailedDescription("Recover your account using an Email address by sending a mail containing a new password.")
} .permissions(ALLOWED, PlayerPermission.RECOVER_EMAIL)
}, "Recover using E-mail", "Recover your account using an E-mail address.", emailBaseCommand); .withArgument("email", "Email address", false)
recoverEmailCommand.setCommandPermissions(PlayerPermission.RECOVER_EMAIL, CommandPermissions.DefaultPermission.ALLOWED); .build();
recoverEmailCommand.addArgument(new CommandArgumentDescription("email", "Email address", false));
// Register the base captcha command // Register the base captcha command
CommandDescription captchaBaseCommand = new CommandDescription(new CaptchaCommand(), new ArrayList<String>() { CommandDescription CAPTCHA_BASE = CommandDescription.builder()
{ .executableCommand(new CaptchaCommand())
add("captcha"); .parent(null)
add("capt"); .labels("captcha", "capt")
} .description("Captcha Command")
}, "Captcha command", "Captcha command for AuthMeReloaded.", null); .detailedDescription("Captcha command for AuthMeRelaoded.")
captchaBaseCommand.setCommandPermissions(PlayerPermission.CAPTCHA, CommandPermissions.DefaultPermission.ALLOWED); .permissions(ALLOWED, PlayerPermission.CAPTCHA)
captchaBaseCommand.addArgument(new CommandArgumentDescription("captcha", "The captcha", false)); .withArgument("captcha", "The Captcha", false)
.build();
// Register the help command // Register the help command
CommandDescription captchaHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription captchaHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded change captcha commands.", captchaBaseCommand); .executableCommand(helpCommandExecutable)
captchaHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(CAPTCHA_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded captcha commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Register the base converter command // Register the base converter command
CommandDescription converterBaseCommand = new CommandDescription(new ConverterCommand(), new ArrayList<String>() { CommandDescription CONVERTER_BASE = CommandDescription.builder()
{ .executableCommand(new ConverterCommand())
add("converter"); .parent(null)
add("convert"); .labels("converter", "convert", "conv")
add("conv"); .description("Converter Command")
} .detailedDescription("Converter command for AuthMeRelaoded.")
}, "Convert command", "Convert command for AuthMeReloaded.", null); .permissions(OP_ONLY, AdminPermission.CONVERTER)
converterBaseCommand.setCommandPermissions(AdminPermission.CONVERTER, OP_ONLY); .withArgument("job", "Conversion job: flattosql / flattosqlite /| xauth / crazylogin / rakamak / royalauth / vauth / sqltoflat", false)
converterBaseCommand.addArgument(new CommandArgumentDescription("job", "Conversion job: flattosql / flattosqlite /| xauth / crazylogin / rakamak / royalauth / vauth / sqltoflat", false)); .build();
// Register the help command // Register the help command
CommandDescription converterHelpCommand = new CommandDescription(helpCommandExecutable, helpCommandLabels, CommandDescription converterHelpCommand = CommandDescription.builder()
"View help", "View detailed help pages about AuthMeReloaded change captcha commands.", converterBaseCommand); .executableCommand(helpCommandExecutable)
converterHelpCommand.addArgument(new CommandArgumentDescription("query", "The command or query to view help for.", true)); .parent(CONVERTER_BASE)
.labels(helpCommandLabels)
.description("View help")
.detailedDescription("View detailed help pages about AuthMeReloaded converter commands.")
.withArgument("query", "The command or query to view help for.", true)
.build();
// Add the base commands to the commands array // Add the base commands to the commands array
baseCommands = Arrays.asList( baseCommands = new HashSet<>(Arrays.asList(
AUTHME_BASE, AUTHME_BASE,
loginBaseCommand, LOGIN_BASE,
logoutBaseCommand, LOGOUT_BASE,
registerBaseCommand, REGISTER_BASE,
unregisterBaseCommand, UNREGISTER_BASE,
changePasswordBaseCommand, CHANGE_PASSWORD_BASE,
emailBaseCommand, EMAIL_BASE,
captchaBaseCommand, CAPTCHA_BASE,
converterBaseCommand); CONVERTER_BASE));
} }
} }

View File

@ -14,12 +14,6 @@ public class CommandParts {
*/ */
private final List<String> parts = new ArrayList<>(); private final List<String> parts = new ArrayList<>();
/**
* Constructor.
*/
public CommandParts() {
}
/** /**
* Constructor. * Constructor.
* *
@ -29,15 +23,6 @@ public class CommandParts {
this.parts.add(part); this.parts.add(part);
} }
/**
* Constructor.
*
* @param commandParts The command parts instance.
*/
public CommandParts(CommandParts commandParts) {
this.parts.addAll(commandParts.getList());
}
/** /**
* Constructor. * Constructor.
* *
@ -47,17 +32,6 @@ public class CommandParts {
this.parts.addAll(parts); this.parts.addAll(parts);
} }
/**
* Constructor.
*
* @param base The base part.
* @param parts The list of additional parts.
*/
public CommandParts(String base, List<String> parts) {
this.parts.add(base);
this.parts.addAll(parts);
}
/** /**
* Get the command parts. * Get the command parts.
* *
@ -67,41 +41,6 @@ public class CommandParts {
return this.parts; return this.parts;
} }
/**
* Add a part.
*
* @param part The part to add.
*
* @return The result.
*/
public boolean add(String part) {
return this.parts.add(part);
}
/**
* Add some parts.
*
* @param parts The parts to add.
*
* @return The result.
*/
public boolean add(List<String> parts) {
return this.parts.addAll(parts);
}
/**
* Add some parts.
*
* @param parts The parts to add.
*
* @return The result.
*/
public boolean add(String[] parts) {
for (String entry : parts)
add(entry);
return true;
}
/** /**
* Get the number of parts. * Get the number of parts.
* *
@ -112,7 +51,7 @@ public class CommandParts {
} }
/** /**
* Get a part by it's index. * Get a part by its index.
* *
* @param i Part index. * @param i Part index.
* *
@ -127,63 +66,6 @@ public class CommandParts {
return this.parts.get(i); return this.parts.get(i);
} }
/**
* Get a range of the parts starting at the specified index up to the end of the range.
*
* @param start The starting index.
*
* @return The parts range. Arguments that were out of bound are not included.
*/
public List<String> getRange(int start) {
return getRange(start, getCount() - start);
}
/**
* Get a range of the parts.
*
* @param start The starting index.
* @param count The number of parts to get.
*
* @return The parts range. Parts that were out of bound are not included.
*/
public List<String> getRange(int start, int count) {
// Create a new list to put the range into
List<String> elements = new ArrayList<>();
// Get the range
for (int i = start; i < start + count; i++) {
// Get the part and add it if it's valid
String element = get(i);
if (element != null)
elements.add(element);
}
// Return the list of parts
return elements;
}
/**
* Get the difference value between two references.
*
* @param other The other reference.
* @param fullCompare True to compare the full references as far as the range reaches.
*
* @return The result from zero to above. A negative number will be returned on error.
*/
public double getDifference(CommandParts other, boolean fullCompare) {
// Make sure the other reference is correct
if (other == null)
return -1;
// Get the range to use
int range = Math.min(this.getCount(), other.getCount());
// Get and the difference
if (fullCompare)
return StringUtils.getDifference(this.toString(), other.toString());
return StringUtils.getDifference(this.getRange(range - 1, 1).toString(), other.getRange(range - 1, 1).toString());
}
/** /**
* Convert the parts to a string. * Convert the parts to a string.
* *

View File

@ -1,6 +1,7 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -22,18 +23,6 @@ public class CommandPermissions {
*/ */
private DefaultPermission defaultPermission; private DefaultPermission defaultPermission;
/**
* Constructor.
*
* @param permissionNode The permission node required to execute a command.
* @param defaultPermission The default permission if the permission nodes couldn't be used.
*/
public CommandPermissions(PermissionNode permissionNode, DefaultPermission defaultPermission) {
this.permissionNodes = new ArrayList<>();
this.permissionNodes.add(permissionNode);
this.defaultPermission = defaultPermission;
}
/** /**
* Constructor. * Constructor.
* *
@ -54,16 +43,6 @@ public class CommandPermissions {
return this.permissionNodes; return this.permissionNodes;
} }
/**
* Get the number of permission nodes set.
*
* @return Permission node count.
*/
public int getPermissionNodeCount() {
return this.permissionNodes.size();
}
/** /**
* Check whether this command requires any permission to be executed. This is based on the getPermission() method. * Check whether this command requires any permission to be executed. This is based on the getPermission() method.
* *
@ -73,31 +52,28 @@ public class CommandPermissions {
*/ */
public boolean hasPermission(CommandSender sender) { public boolean hasPermission(CommandSender sender) {
// Make sure any permission node is set // Make sure any permission node is set
if (getPermissionNodeCount() == 0) if (permissionNodes.isEmpty()) {
return true; return true;
}
// Get the default permission PermissionsManager permissionsManager = AuthMe.getInstance().getPermissionsManager();
final boolean defaultPermission = getDefaultPermissionCommandSender(sender); final boolean defaultPermission = getDefaultPermissionCommandSender(sender);
// Make sure the command sender is a player, if not use the default // Make sure the command sender is a player, if not use the default
if (!(sender instanceof Player)) if (!(sender instanceof Player)) {
return defaultPermission; return defaultPermission;
}
// Get the player instance // Get the player instance
Player player = (Player) sender; Player player = (Player) sender;
// Get the permissions manager, and make sure it's instance is valid // Get the permissions manager, and make sure it's instance is valid
PermissionsManager permissionsManager = AuthMe.getInstance().getPermissionsManager();
if (permissionsManager == null) if (permissionsManager == null)
return false; return false;
// Check whether the player has permission, return the result // Check whether the player has permission, return the result
for (PermissionNode node : this.permissionNodes) { return permissionsManager.hasPermission(player, this.permissionNodes, defaultPermission);
if (!permissionsManager.hasPermission(player, node, defaultPermission)) {
return false;
}
}
return true;
} }
/** /**
@ -109,14 +85,6 @@ public class CommandPermissions {
return this.defaultPermission; return this.defaultPermission;
} }
/**
* Set the default permission used if the permission nodes couldn't be used.
*
* @param defaultPermission The default permission.
*/
public void setDefaultPermission(DefaultPermission defaultPermission) {
this.defaultPermission = defaultPermission;
}
/** /**
* Get the default permission for a specified command sender. * Get the default permission for a specified command sender.
@ -138,12 +106,4 @@ public class CommandPermissions {
return false; return false;
} }
} }
/**
*/
public enum DefaultPermission {
NOT_ALLOWED,
OP_ONLY,
ALLOWED
}
} }

View File

@ -1,5 +1,11 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
public final class CommandUtils { public final class CommandUtils {
public static int getMinNumberOfArguments(CommandDescription command) { public static int getMinNumberOfArguments(CommandDescription command) {
@ -13,9 +19,40 @@ public final class CommandUtils {
} }
public static int getMaxNumberOfArguments(CommandDescription command) { public static int getMaxNumberOfArguments(CommandDescription command) {
return command.hasMaximumArguments() return command.getArguments().size();
? command.getArguments().size()
: -1;
} }
/**
* Provide a textual representation of a list of labels to show it as a command. For example, a list containing
* the items ["authme", "register", "player"] it will return "authme register player".
*
* @param labels The labels to format
* @return The space-separated labels
*/
public static String labelsToString(Iterable<String> labels) {
return StringUtils.join(" ", labels);
}
public static double getDifference(List<String> labels1, List<String> labels2, boolean fullCompare) {
// Make sure the other reference is correct
if (labels1 == null || labels2 == null) {
return -1;
}
// Get the range to use
int range = Math.min(labels1.size(), labels2.size());
// Get and the difference
if (fullCompare) {
return StringUtils.getDifference(CommandUtils.labelsToString(labels1), CommandUtils.labelsToString(labels2));
}
return StringUtils.getDifference(
labelsToString(CollectionUtils.getRange(labels1, range - 1, 1)),
labelsToString(CollectionUtils.getRange(labels2, range - 1, 1)));
}
} }

View File

@ -61,27 +61,13 @@ public class FoundCommandResult {
return this.commandDescription; return this.commandDescription;
} }
/**
* Set the command description.
*
* @param commandDescription The command description.
*/
public void setCommandDescription(CommandDescription commandDescription) {
this.commandDescription = commandDescription;
}
/** /**
* Check whether the command is executable. * Check whether the command is executable.
* *
* @return True if the command is executable, false otherwise. * @return True if the command is executable, false otherwise.
*/ */
public boolean isExecutable() { public boolean isExecutable() {
// Make sure the command description is valid return commandDescription != null;
if (this.commandDescription == null)
return false;
// Check whether the command is executable, return the result
return this.commandDescription.isExecutable();
} }
/** /**
@ -153,10 +139,11 @@ public class FoundCommandResult {
*/ */
public double getDifference() { public double getDifference() {
// Get the difference through the command found // Get the difference through the command found
if (this.commandDescription != null) if (this.commandDescription != null) {
return this.commandDescription.getCommandDifference(this.queryReference); return this.commandDescription.getCommandDifference(this.queryReference);
}
// Get the difference from the query reference // Get the difference from the query reference
return this.queryReference.getDifference(commandReference, true); return CommandUtils.getDifference(queryReference.getList(), commandReference.getList(), true);
} }
} }

View File

@ -18,7 +18,7 @@ import java.security.NoSuchAlgorithmException;
/** /**
* Admin command for changing a player's password. * Admin command for changing a player's password.
*/ */
public class ChangePasswordCommand extends ExecutableCommand { public class ChangePasswordAdminCommand extends ExecutableCommand {
@Override @Override
public boolean executeCommand(final CommandSender sender, CommandParts commandReference, CommandParts commandArguments) { public boolean executeCommand(final CommandSender sender, CommandParts commandReference, CommandParts commandArguments) {

View File

@ -15,8 +15,9 @@ import org.bukkit.command.CommandSender;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
/** /**
* Admin command to register a user.
*/ */
public class RegisterCommand extends ExecutableCommand { public class RegisterAdminCommand extends ExecutableCommand {
/** /**
* Execute the command. * Execute the command.
@ -42,8 +43,12 @@ public class RegisterCommand extends ExecutableCommand {
final String playerPassLowerCase = playerPass.toLowerCase(); final String playerPassLowerCase = playerPass.toLowerCase();
// Command logic // Command logic
if (playerPassLowerCase.contains("delete") || playerPassLowerCase.contains("where") || playerPassLowerCase.contains("insert") || playerPassLowerCase.contains("modify") || playerPassLowerCase.contains("from") || playerPassLowerCase.contains("select") || playerPassLowerCase.contains(";") || playerPassLowerCase.contains("null") || !playerPassLowerCase.matches(Settings.getPassRegex)) { if (playerPassLowerCase.contains("delete") || playerPassLowerCase.contains("where")
m.send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); || playerPassLowerCase.contains("insert") || playerPassLowerCase.contains("modify")
|| playerPassLowerCase.contains("from") || playerPassLowerCase.contains("select")
|| playerPassLowerCase.contains(";") || playerPassLowerCase.contains("null")
|| !playerPassLowerCase.matches(Settings.getPassRegex)) {
m.send(sender, MessageKey.PASSWORD_MATCH_ERROR);
return true; return true;
} }
if (playerPassLowerCase.equalsIgnoreCase(playerName)) { if (playerPassLowerCase.equalsIgnoreCase(playerName)) {

View File

@ -2,11 +2,15 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AntiBot; import fr.xephi.authme.AntiBot;
import fr.xephi.authme.command.CommandParts; import fr.xephi.authme.command.CommandParts;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.util.CollectionUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.List;
/** /**
*/ */
public class SwitchAntiBotCommand extends ExecutableCommand { public class SwitchAntiBotCommand extends ExecutableCommand {
@ -32,16 +36,16 @@ public class SwitchAntiBotCommand extends ExecutableCommand {
} }
// Enable the mod // Enable the mod
if (newState.equalsIgnoreCase("ON")) { if ("ON".equalsIgnoreCase(newState)) {
AntiBot.overrideAntiBotStatus(true); AntiBot.overrideAntiBotStatus(true);
sender.sendMessage("[AuthMe] AntiBot Manual Ovverride: enabled!"); sender.sendMessage("[AuthMe] AntiBot Manual Override: enabled!");
return true; return true;
} }
// Disable the mod // Disable the mod
if (newState.equalsIgnoreCase("OFF")) { if ("OFF".equalsIgnoreCase(newState)) {
AntiBot.overrideAntiBotStatus(false); AntiBot.overrideAntiBotStatus(false);
sender.sendMessage("[AuthMe] AntiBotMod Manual Ovverride: disabled!"); sender.sendMessage("[AuthMe] AntiBotMod Manual Override: disabled!");
return true; return true;
} }
@ -52,8 +56,9 @@ public class SwitchAntiBotCommand extends ExecutableCommand {
HelpProvider.showHelp(sender, commandReference, commandReference, true, false, true, false, false, false); HelpProvider.showHelp(sender, commandReference, commandReference, true, false, true, false, false, false);
// Show the command to use for detailed help // Show the command to use for detailed help
CommandParts helpCommandReference = new CommandParts(commandReference.getRange(1)); List<String> helpCommandReference = CollectionUtils.getRange(commandReference.getList(), 1);
sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/" + commandReference.get(0) + " help " + helpCommandReference); sender.sendMessage(ChatColor.GOLD + "Detailed help: " + ChatColor.WHITE + "/"
+ commandReference.get(0) + " help " + CommandUtils.labelsToString(helpCommandReference));
return true; return true;
} }
} }

View File

@ -21,8 +21,9 @@ import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
/** /**
* Admin command to unregister a player.
*/ */
public class UnregisterCommand extends ExecutableCommand { public class UnregisterAdminCommand extends ExecutableCommand {
/** /**
* Execute the command. * Execute the command.

View File

@ -5,14 +5,15 @@ import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandParts; import fr.xephi.authme.command.CommandParts;
import fr.xephi.authme.command.CommandPermissions; import fr.xephi.authme.command.CommandPermissions;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -77,10 +78,6 @@ public class HelpPrinter {
// Print the syntax // Print the syntax
sender.sendMessage(argString.toString()); sender.sendMessage(argString.toString());
} }
// Show the unlimited arguments argument
if (!command.hasMaximumArguments())
sender.sendMessage(" " + ChatColor.YELLOW + ChatColor.ITALIC + "... : " + ChatColor.WHITE + "Any additional arguments." + ChatColor.GRAY + ChatColor.ITALIC + " (Optional)");
} }
/** /**
@ -90,14 +87,11 @@ public class HelpPrinter {
* @param command The command to print the permissions help for. * @param command The command to print the permissions help for.
*/ */
public static void printPermissions(CommandSender sender, CommandDescription command) { public static void printPermissions(CommandSender sender, CommandDescription command) {
// Get the permissions and make sure it isn't null // Get the permissions and make sure they aren't missing
CommandPermissions permissions = command.getCommandPermissions(); CommandPermissions permissions = command.getCommandPermissions();
if (permissions == null) if (permissions == null || CollectionUtils.isEmpty(permissions.getPermissionNodes())) {
return;
// Make sure any permission node is set
if (permissions.getPermissionNodeCount() <= 0)
return; return;
}
// Print the header // Print the header
sender.sendMessage(ChatColor.GOLD + "Permissions:"); sender.sendMessage(ChatColor.GOLD + "Permissions:");
@ -112,13 +106,16 @@ public class HelpPrinter {
} }
// Print the default permission // Print the default permission
// TODO ljacqu 20151205: This is duplicating the logic in PermissionsManager#evaluateDefaultPermission
// Either use the command manager here, or if that's too heavy, look into moving certain permissions logic
// into a Utils class
switch (permissions.getDefaultPermission()) { switch (permissions.getDefaultPermission()) {
case ALLOWED: case ALLOWED:
sender.sendMessage(ChatColor.GOLD + " Default: " + ChatColor.GRAY + ChatColor.ITALIC + "Permission!"); sender.sendMessage(ChatColor.GOLD + " Default: " + ChatColor.GRAY + ChatColor.ITALIC + "Permission!");
break; break;
case OP_ONLY: case OP_ONLY:
final String defaultPermsString = ChatColor.GRAY + (permissions.getDefaultPermissionCommandSender(sender) ? ChatColor.ITALIC + " (Permission!)" : ChatColor.ITALIC + " (No Permission!)"); final String defaultPermsString = ChatColor.GRAY + (sender.isOp() ? ChatColor.ITALIC + " (Permission!)" : ChatColor.ITALIC + " (No Permission!)");
sender.sendMessage(ChatColor.GOLD + " Default: " + ChatColor.YELLOW + ChatColor.ITALIC + "OP's Only!" + defaultPermsString); sender.sendMessage(ChatColor.GOLD + " Default: " + ChatColor.YELLOW + ChatColor.ITALIC + "OP's Only!" + defaultPermsString);
break; break;

View File

@ -3,12 +3,17 @@ package fr.xephi.authme.command.help;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandParts; import fr.xephi.authme.command.CommandParts;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.CollectionUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.ArrayList;
import java.util.List;
/** /**
*/ */
public class HelpProvider { public class HelpProvider {
@ -40,7 +45,12 @@ public class HelpProvider {
public static void showHelp(CommandSender sender, CommandParts reference, CommandParts helpQuery, boolean showCommand, boolean showDescription, boolean showArguments, boolean showPermissions, boolean showAlternatives, boolean showCommands) { public static void showHelp(CommandSender sender, CommandParts reference, CommandParts helpQuery, boolean showCommand, boolean showDescription, boolean showArguments, boolean showPermissions, boolean showAlternatives, boolean showCommands) {
// Find the command for this help query, one with and one without a prefixed base command // Find the command for this help query, one with and one without a prefixed base command
FoundCommandResult result = AuthMe.getInstance().getCommandHandler().findCommand(new CommandParts(helpQuery.getList())); FoundCommandResult result = AuthMe.getInstance().getCommandHandler().findCommand(new CommandParts(helpQuery.getList()));
CommandParts commandReferenceOther = new CommandParts(reference.get(0), helpQuery.getList());
// TODO ljacqu 20151204 Fix me to nicer code
List<String> parts = new ArrayList<>(helpQuery.getList());
parts.add(0, reference.get(0));
CommandParts commandReferenceOther = new CommandParts(parts);
FoundCommandResult resultOther = AuthMe.getInstance().getCommandHandler().findCommand(commandReferenceOther); FoundCommandResult resultOther = AuthMe.getInstance().getCommandHandler().findCommand(commandReferenceOther);
if (resultOther != null) { if (resultOther != null) {
if (result == null) if (result == null)
@ -78,13 +88,14 @@ public class HelpProvider {
// Show the unknown command warning // Show the unknown command warning
sender.sendMessage(ChatColor.DARK_RED + "No help found for '" + helpQuery + "'!"); sender.sendMessage(ChatColor.DARK_RED + "No help found for '" + helpQuery + "'!");
// Get the suggested command
CommandParts suggestedCommandParts = new CommandParts(result.getCommandDescription().getCommandReference(commandReference).getRange(1));
// Show a command suggestion if available and the difference isn't too big // Show a command suggestion if available and the difference isn't too big
if (commandDifference < 0.75) if (commandDifference < 0.75 && result.getCommandDescription() != null) {
if (result.getCommandDescription() != null) // Get the suggested command
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD + "/" + baseCommand + " help " + suggestedCommandParts + ChatColor.YELLOW + "?"); List<String> suggestedCommandParts = CollectionUtils.getRange(
result.getCommandDescription().getCommandReference(commandReference).getList(), 1);
sender.sendMessage(ChatColor.YELLOW + "Did you mean " + ChatColor.GOLD + "/" + baseCommand
+ " help " + CommandUtils.labelsToString(suggestedCommandParts) + ChatColor.YELLOW + "?");
}
// Show the help command // Show the help command
sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + baseCommand + " help" + ChatColor.YELLOW + " to view help."); sender.sendMessage(ChatColor.YELLOW + "Use the command " + ChatColor.GOLD + "/" + baseCommand + " help" + ChatColor.YELLOW + " to view help.");
@ -94,10 +105,12 @@ public class HelpProvider {
// Show a message when the command handler is assuming a command // Show a message when the command handler is assuming a command
if (commandDifference > 0) { if (commandDifference > 0) {
// Get the suggested command // Get the suggested command
CommandParts suggestedCommandParts = new CommandParts(result.getCommandDescription().getCommandReference(commandReference).getRange(1)); List<String> suggestedCommandParts = CollectionUtils.getRange(
result.getCommandDescription().getCommandReference(commandReference).getList(), 1);
// Show the suggested command // Show the suggested command
sender.sendMessage(ChatColor.DARK_RED + "No help found, assuming '" + ChatColor.GOLD + suggestedCommandParts + ChatColor.DARK_RED + "'!"); sender.sendMessage(ChatColor.DARK_RED + "No help found, assuming '" + ChatColor.GOLD
+ CommandUtils.labelsToString(suggestedCommandParts) + ChatColor.DARK_RED + "'!");
} }
// Print the help header // Print the help header

View File

@ -3,6 +3,8 @@ package fr.xephi.authme.command.help;
import fr.xephi.authme.command.CommandArgumentDescription; import fr.xephi.authme.command.CommandArgumentDescription;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandParts; import fr.xephi.authme.command.CommandParts;
import fr.xephi.authme.command.CommandUtils;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -35,8 +37,8 @@ public final class HelpSyntaxHelper {
// Get the help command reference, and the command label // Get the help command reference, and the command label
CommandParts helpCommandReference = commandDescription.getCommandReference(commandReference); CommandParts helpCommandReference = commandDescription.getCommandReference(commandReference);
final String parentCommand = new CommandParts( final String parentCommand = CommandUtils.labelsToString(
helpCommandReference.getRange(0, helpCommandReference.getCount() - 1)).toString(); CollectionUtils.getRange(helpCommandReference.getList(), 0, helpCommandReference.getCount() - 1));
// Check whether the alternative label should be used // Check whether the alternative label should be used
String commandLabel; String commandLabel;
@ -61,11 +63,6 @@ public final class HelpSyntaxHelper {
sb.append(ChatColor.ITALIC).append(formatArgument(arg)); sb.append(ChatColor.ITALIC).append(formatArgument(arg));
} }
// Add some dots if the command allows unlimited arguments
if (!commandDescription.hasMaximumArguments()) {
sb.append(ChatColor.ITALIC).append(" ...");
}
// Return the build command syntax // Return the build command syntax
return sb.toString(); return sb.toString();
} }

View File

@ -8,112 +8,108 @@ public enum AdminPermission implements PermissionNode {
/** /**
* Administrator command to register a new user. * Administrator command to register a new user.
*/ */
REGISTER("authme.command.admin.register"), REGISTER("authme.admin.register"),
/** /**
* Administrator command to unregister an existing user. * Administrator command to unregister an existing user.
*/ */
UNREGISTER("authme.command.admin.unregister"), UNREGISTER("authme.admin.unregister"),
/** /**
* Administrator command to force-login an existing user. * Administrator command to force-login an existing user.
*/ */
FORCE_LOGIN("authme.command.admin.forcelogin"), FORCE_LOGIN("authme.admin.forcelogin"),
/** /**
* Administrator command to change the password of a user. * Administrator command to change the password of a user.
*/ */
CHANGE_PASSWORD("authme.command.admin.changepassword"), CHANGE_PASSWORD("authme.admin.changepassword"),
/** /**
* Administrator command to see the last login date and time of an user. * Administrator command to see the last login date and time of a user.
*/ */
LAST_LOGIN("authme.command.admin.lastlogin"), LAST_LOGIN("authme.admin.lastlogin"),
/** /**
* Administrator command to see all accounts associated with an user. * Administrator command to see all accounts associated with a user.
*/ */
ACCOUNTS("authme.command.admin.accounts"), ACCOUNTS("authme.admin.accounts"),
/** /**
* Administrator command to get the email address of an user, if set. * Administrator command to get the email address of a user, if set.
*/ */
GET_EMAIL("authme.command.admin.getemail"), GET_EMAIL("authme.admin.getemail"),
/** /**
* Administrator command to set or change the email adress of an user. * Administrator command to set or change the email address of a user.
*/ */
CHANGE_EMAIL("authme.command.admin.changemail"), CHANGE_EMAIL("authme.admin.changemail"),
/** /**
* Administrator command to get the last known IP of an user. * Administrator command to get the last known IP of a user.
*/ */
GET_IP("authme.command.admin.getip"), GET_IP("authme.admin.getip"),
/** /**
* Administrator command to teleport to the AuthMe spawn. * Administrator command to teleport to the AuthMe spawn.
*/ */
SPAWN("authme.command.admin.spawn"), SPAWN("authme.admin.spawn"),
/** /**
* Administrator command to set the AuthMe spawn. * Administrator command to set the AuthMe spawn.
*/ */
SET_SPAWN("authme.command.admin.setspawn"), SET_SPAWN("authme.admin.setspawn"),
/** /**
* Administrator command to teleport to the first AuthMe spawn. * Administrator command to teleport to the first AuthMe spawn.
*/ */
FIRST_SPAWN("authme.command.admin.firstspawn"), FIRST_SPAWN("authme.admin.firstspawn"),
/** /**
* Administrator command to set the first AuthMe spawn. * Administrator command to set the first AuthMe spawn.
*/ */
SET_FIRST_SPAWN("authme.command.admin.setfirstspawn"), SET_FIRST_SPAWN("authme.admin.setfirstspawn"),
/** /**
* Administrator command to purge old user data. * Administrator command to purge old user data.
*/ */
PURGE("authme.command.admin.purge"), PURGE("authme.admin.purge"),
/** /**
* Administrator command to purge the last position of an user. * Administrator command to purge the last position of a user.
*/ */
PURGE_LAST_POSITION("authme.command.admin.purgelastpos"), PURGE_LAST_POSITION("authme.admin.purgelastpos"),
/** /**
* Administrator command to purge all data associated with banned players. * Administrator command to purge all data associated with banned players.
*/ */
PURGE_BANNED_PLAYERS("authme.command.admin.purgebannedplayers"), PURGE_BANNED_PLAYERS("authme.admin.purgebannedplayers"),
/** /**
* Administrator command to toggle the AntiBot protection status. * Administrator command to toggle the AntiBot protection status.
*/ */
SWITCH_ANTIBOT("authme.command.admin.switchantibot"), SWITCH_ANTIBOT("authme.admin.switchantibot"),
/** /**
* Administrator command to convert old or other data to AuthMe data. * Administrator command to convert old or other data to AuthMe data.
*/ */
CONVERTER("authme.command.admin.converter"), CONVERTER("authme.admin.converter"),
/** /**
* Administrator command to reload the plugin configuration. * Administrator command to reload the plugin configuration.
*/ */
RELOAD("authme.command.admin.reload"); RELOAD("authme.admin.reload"),
/** /**
* Permission node. * Give access to all admin commands.
*/
ADMIN_ALL("authme.admin.*");
/**
* The permission node.
*/ */
private String node; private String node;
/**
* Get the permission node.
* @return
*/
@Override
public String getNode() {
return node;
}
/** /**
* Constructor. * Constructor.
* *
@ -122,4 +118,14 @@ public enum AdminPermission implements PermissionNode {
AdminPermission(String node) { AdminPermission(String node) {
this.node = node; this.node = node;
} }
@Override
public String getNode() {
return node;
}
@Override
public PermissionNode getWildcardNode() {
return ADMIN_ALL;
}
} }

View File

@ -0,0 +1,16 @@
package fr.xephi.authme.permission;
/**
* The default permission for a command if there is no support for permission nodes.
*/
public enum DefaultPermission {
/** No one can execute the command. */
NOT_ALLOWED,
/** Only players with the OP status may execute the command. */
OP_ONLY,
/** The command can be executed by anyone. */
ALLOWED
}

View File

@ -5,7 +5,18 @@ package fr.xephi.authme.permission;
*/ */
public interface PermissionNode { public interface PermissionNode {
/** Return the node of the permission, e.g. "authme.unregister". */ /**
* Return the node of the permission, e.g. "authme.player.unregister".
*
* @return The name of the permission node
*/
String getNode(); String getNode();
/**
* Return the wildcard node that also grants the permission.
*
* @return The wildcard permission node (e.g. "authme.player.*")
*/
PermissionNode getWildcardNode();
} }

View File

@ -5,11 +5,14 @@ import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions; import com.nijikokun.bukkit.Permissions.Permissions;
import de.bananaco.bpermissions.api.ApiLayer; import de.bananaco.bpermissions.api.ApiLayer;
import de.bananaco.bpermissions.api.CalculableType; import de.bananaco.bpermissions.api.CalculableType;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.util.CollectionUtils;
import net.milkbowl.vault.permission.Permission; import net.milkbowl.vault.permission.Permission;
import org.anjocaido.groupmanager.GroupManager; import org.anjocaido.groupmanager.GroupManager;
import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.event.server.PluginEnableEvent;
@ -38,7 +41,7 @@ import java.util.logging.Logger;
* @author Tim Visée, http://timvisee.com * @author Tim Visée, http://timvisee.com
* @version 0.2.1 * @version 0.2.1
*/ */
public class PermissionsManager { public class PermissionsManager implements PermissionsService {
/** /**
* Vault instance. * Vault instance.
@ -100,8 +103,8 @@ public class PermissionsManager {
* *
* @return The name of the permissions system used. * @return The name of the permissions system used.
*/ */
public String getUsedPermissionsSystemType() { public PermissionsSystemType getSystem() {
return this.permsType.getName(); return permsType;
} }
/** /**
@ -260,7 +263,6 @@ public class PermissionsManager {
* *
* @param event Event instance. * @param event Event instance.
*/ */
// TODO ljacqu 20151129: Misleading name since onPluginEnable is a typical event-based method name
public void onPluginEnable(PluginEnableEvent event) { public void onPluginEnable(PluginEnableEvent event) {
// Get the plugin and it's name // Get the plugin and it's name
Plugin plugin = event.getPlugin(); Plugin plugin = event.getPlugin();
@ -296,35 +298,7 @@ public class PermissionsManager {
} }
} }
/**
* Get the logger instance.
*
* @return Logger instance.
*/
public Logger getLogger() {
return this.log;
}
/**
* Set the logger instance.
*
* @param log Logger instance.
*/
public void setLogger(Logger log) {
this.log = log;
}
/**
* Check if the player has permission. If no permissions system is used, the player has to be OP.
*
* @param player The player.
* @param permsNode Permissions node.
*
* @return True if the player has permission.
*/
public boolean hasPermission(Player player, String permsNode) {
return hasPermission(player, permsNode, player.isOp());
}
/** /**
* Check if the player has permission for the given permissions node. If no permissions system is used, * Check if the player has permission for the given permissions node. If no permissions system is used,
@ -340,7 +314,42 @@ public class PermissionsManager {
} }
public boolean hasPermission(Player player, PermissionNode permissionNode, boolean def) { public boolean hasPermission(Player player, PermissionNode permissionNode, boolean def) {
return hasPermission(player, permissionNode.getNode(), def); return hasPermission(player, permissionNode.getNode(), def)
|| hasPermission(player, permissionNode.getWildcardNode().getNode(), def);
}
public boolean hasPermission(Player player, Iterable<PermissionNode> nodes, boolean def) {
for (PermissionNode node : nodes) {
if (!hasPermission(player, node, def)) {
return false;
}
}
return true;
}
public boolean hasPermission(Player player, CommandDescription command) {
if (command.getCommandPermissions() == null
|| CollectionUtils.isEmpty(command.getCommandPermissions().getPermissionNodes())) {
return true;
}
DefaultPermission defaultPermission = command.getCommandPermissions().getDefaultPermission();
boolean def = evaluateDefaultPermission(defaultPermission, player);
return hasPermission(player, command.getCommandPermissions().getPermissionNodes(), def);
}
public static boolean evaluateDefaultPermission(DefaultPermission defaultPermission, CommandSender sender) {
switch (defaultPermission) {
case ALLOWED:
return true;
case OP_ONLY:
return sender.isOp();
case NOT_ALLOWED:
default:
return false;
}
} }
/** /**
@ -352,7 +361,7 @@ public class PermissionsManager {
* *
* @return True if the player has permission. * @return True if the player has permission.
*/ */
public boolean hasPermission(Player player, String permsNode, boolean def) { private boolean hasPermission(Player player, String permsNode, boolean def) {
// If no permissions system is used, return the default value // If no permissions system is used, return the default value
if (!isEnabled()) if (!isEnabled())
return def; return def;
@ -915,34 +924,5 @@ public class PermissionsManager {
return removeGroups(player, groupNames); return removeGroups(player, groupNames);
} }
private enum PermissionsSystemType {
NONE("None"),
PERMISSIONS_EX("PermissionsEx"),
PERMISSIONS_BUKKIT("Permissions Bukkit"),
B_PERMISSIONS("bPermissions"),
ESSENTIALS_GROUP_MANAGER("Essentials Group Manager"),
Z_PERMISSIONS("zPermissions"),
VAULT("Vault"),
PERMISSIONS("Permissions");
public final String name;
/**
* Constructor for PermissionsSystemType.
*
* @param name String
*/
PermissionsSystemType(String name) {
this.name = name;
}
/**
* Method getName.
*
* @return String
*/
public String getName() {
return this.name;
}
}
} }

View File

@ -0,0 +1,39 @@
package fr.xephi.authme.permission;
import fr.xephi.authme.command.CommandDescription;
import org.bukkit.entity.Player;
/**
* Interface for dealing with permissions.
*/
public interface PermissionsService {
/**
* Check if the player has the given permission.
*
* @param player The player
* @param permission The permission node to check
* @param def Default returned if no permissions system is used
*
* @return True if the player has permission
*/
boolean hasPermission(Player player, PermissionNode permission, boolean def);
/**
* Check if the player has the permissions for the given command.
*
* @param player The player
* @param command The command whose permissions should be checked
*
* @return True if the player may execute the command
*/
boolean hasPermission(Player player, CommandDescription command);
/**
* Return the permission system the service is working with.
*
* @return The permission system AuthMe is hooked into
*/
PermissionsSystemType getSystem();
}

View File

@ -0,0 +1,38 @@
package fr.xephi.authme.permission;
/**
* Enum representing the permissions systems AuthMe supports.
*/
public enum PermissionsSystemType {
NONE("None"),
PERMISSIONS_EX("PermissionsEx"),
PERMISSIONS_BUKKIT("Permissions Bukkit"),
B_PERMISSIONS("bPermissions"),
ESSENTIALS_GROUP_MANAGER("Essentials Group Manager"),
Z_PERMISSIONS("zPermissions"),
VAULT("Vault"),
PERMISSIONS("Permissions");
public final String name;
/**
* Constructor for PermissionsSystemType.
*
* @param name The name the permissions manager goes by
*/
PermissionsSystemType(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}

View File

@ -18,47 +18,47 @@ public enum PlayerPermission implements PermissionNode {
/** /**
* Command permission to login. * Command permission to login.
*/ */
LOGIN("authme.command.player.login"), LOGIN("authme.player.login"),
/** /**
* Command permission to logout. * Command permission to logout.
*/ */
LOGOUT("authme.command.player.logout"), LOGOUT("authme.player.logout"),
/** /**
* Command permission to register. * Command permission to register.
*/ */
REGISTER("authme.command.player.register"), REGISTER("authme.player.register"),
/** /**
* Command permission to unregister. * Command permission to unregister.
*/ */
UNREGISTER("authme.command.player.unregister"), UNREGISTER("authme.player.unregister"),
/** /**
* Command permission to change the password. * Command permission to change the password.
*/ */
CHANGE_PASSWORD("authme.command.player.changepassword"), CHANGE_PASSWORD("authme.player.changepassword"),
/** /**
* Command permission to add an email address. * Command permission to add an email address.
*/ */
ADD_EMAIL("authme.command.player.email.add"), ADD_EMAIL("authme.player.email.add"),
/** /**
* Command permission to change the email address. * Command permission to change the email address.
*/ */
CHANGE_EMAIL("authme.command.player.email.change"), CHANGE_EMAIL("authme.player.email.change"),
/** /**
* Command permission to recover an account using it's email address. * Command permission to recover an account using it's email address.
*/ */
RECOVER_EMAIL("authme.command.player.email.recover"), RECOVER_EMAIL("authme.player.email.recover"),
/** /**
* Command permission to use captcha. * Command permission to use captcha.
*/ */
CAPTCHA("authme.command.player.captcha"), CAPTCHA("authme.player.captcha"),
/** /**
* Permission for users a login can be forced to. * Permission for users a login can be forced to.
@ -68,33 +68,28 @@ public enum PlayerPermission implements PermissionNode {
/** /**
* Permission for users to bypass force-survival mode. * Permission for users to bypass force-survival mode.
*/ */
BYPASS_FORCE_SURVIVAL("authme.command.player.bypassforcesurvival"), BYPASS_FORCE_SURVIVAL("authme.player.bypassforcesurvival"),
/** /**
* Permission for users to allow two accounts. * Permission for users to allow two accounts.
*/ */
ALLOW_MULTIPLE_ACCOUNTS("authme.command.player.allow2accounts"), ALLOW_MULTIPLE_ACCOUNTS("authme.player.allow2accounts"),
/** /**
* Permission for user to see other accounts. * Permission for user to see other accounts.
*/ */
SEE_OTHER_ACCOUNTS("authme.command.player.seeotheraccounts"); SEE_OTHER_ACCOUNTS("authme.player.seeotheraccounts"),
/** /**
* Permission node. * Permission to use all player (non-admin) commands.
*/
PLAYER_ALL("authme.player.*");
/**
* The permission node.
*/ */
private String node; private String node;
/**
* Get the permission node.
*
* @return Permission node.
*/
@Override
public String getNode() {
return node;
}
/** /**
* Constructor. * Constructor.
* *
@ -103,4 +98,14 @@ public enum PlayerPermission implements PermissionNode {
PlayerPermission(String node) { PlayerPermission(String node) {
this.node = node; this.node = node;
} }
@Override
public String getNode() {
return node;
}
@Override
public PermissionNode getWildcardNode() {
return PLAYER_ALL;
}
} }

View File

@ -80,15 +80,12 @@ public class AsynchronousLogin {
plugin.captcha.remove(name); plugin.captcha.remove(name);
plugin.captcha.putIfAbsent(name, i); plugin.captcha.putIfAbsent(name, i);
} }
if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) >= Settings.maxLoginTry) { if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) > Settings.maxLoginTry) {
plugin.cap.put(name, rdm.nextString()); plugin.cap.putIfAbsent(name, rdm.nextString());
for (String s : m.retrieve(MessageKey.USAGE_CAPTCHA)) { for (String s : m.retrieve(MessageKey.USAGE_CAPTCHA)) {
player.sendMessage(s.replace("THE_CAPTCHA", plugin.cap.get(name)).replace("<theCaptcha>", plugin.cap.get(name))); player.sendMessage(s.replace("THE_CAPTCHA", plugin.cap.get(name)).replace("<theCaptcha>", plugin.cap.get(name)));
} }
return true; return true;
} else if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) >= Settings.maxLoginTry) {
plugin.captcha.remove(name);
plugin.cap.remove(name);
} }
} }
return false; return false;
@ -135,6 +132,13 @@ public class AsynchronousLogin {
m.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED); m.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
return null; return null;
} }
if (Settings.preventOtherCase && !player.getName().equals(pAuth.getRealName()))
{
// TODO: Add a message like : MessageKey.INVALID_NAME_CASE
m.send(player, MessageKey.USERNAME_ALREADY_ONLINE_ERROR);
return null;
}
AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player); AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player);
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.canLogin()) if (!event.canLogin())

View File

@ -73,7 +73,7 @@ public final class Settings {
enableProtection, enableAntiBot, recallEmail, useWelcomeMessage, enableProtection, enableAntiBot, recallEmail, useWelcomeMessage,
broadcastWelcomeMessage, forceRegKick, forceRegLogin, broadcastWelcomeMessage, forceRegKick, forceRegLogin,
checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect, checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect,
customAttributes, generateImage, isRemoveSpeedEnabled; customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase;
public static String helpHeader, getNickRegex, getUnloggedinGroup, getMySQLHost, public static String helpHeader, getNickRegex, getUnloggedinGroup, getMySQLHost,
getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase, getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase,
getMySQLTablename, getMySQLColumnName, getMySQLColumnPassword, getMySQLTablename, getMySQLColumnName, getMySQLColumnPassword,
@ -294,6 +294,7 @@ public final class Settings {
forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole"); forceRegisterCommandsAsConsole = configFile.getStringList("settings.forceRegisterCommandsAsConsole");
customAttributes = configFile.getBoolean("Hooks.customAttributes"); customAttributes = configFile.getBoolean("Hooks.customAttributes");
generateImage = configFile.getBoolean("Email.generateImage", false); generateImage = configFile.getBoolean("Email.generateImage", false);
preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false);
// Load the welcome message // Load the welcome message
getWelcomeMessage(); getWelcomeMessage();
@ -713,6 +714,12 @@ public final class Settings {
changes = true; changes = true;
} }
if (!contains("settings.preventOtherCase"))
{
set("settings.preventOtherCase", false);
changes = true;
}
if (contains("Email.mailText")) if (contains("Email.mailText"))
{ {
set("Email.mailText", null); set("Email.mailText", null);

View File

@ -0,0 +1,52 @@
package fr.xephi.authme.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Utils class for collections.
*/
public final class CollectionUtils {
private CollectionUtils() {
}
/**
* Get a range from a list based on start and count parameters in a safe way.
*
* @param start The start index
* @param count The number of elements to add
*
* @return The sublist consisting at most of {@code count} elements (less if the parameters
* exceed the size of the list)
*/
public static <T> List<T> getRange(List<T> list, int start, int count) {
if (start >= list.size() || count <= 0) {
return new ArrayList<>();
} else if (start < 0) {
start = 0;
}
int end = Math.min(list.size(), start + count);
return list.subList(start, end);
}
/**
* Get all elements from a list starting from the given index.
*
* @param start The start index
*
* @return The sublist of all elements from index {@code start} and on; empty list
* if the start index exceeds the list's size
*/
public static <T> List<T> getRange(List<T> list, int start) {
if (start >= list.size()) {
return new ArrayList<>();
}
return getRange(list, start, list.size() - start);
}
public static <T> boolean isEmpty(Collection<T> coll) {
return coll == null || coll.isEmpty();
}
}

View File

@ -13,8 +13,6 @@ import java.util.Arrays;
*/ */
public final class StringUtils { public final class StringUtils {
public static final String newline = System.getProperty("line.separator");
private StringUtils() { private StringUtils() {
// Utility class // Utility class
} }
@ -29,8 +27,9 @@ public final class StringUtils {
*/ */
public static double getDifference(String first, String second) { public static double getDifference(String first, String second) {
// Make sure the strings are valid. // Make sure the strings are valid.
if (first == null || second == null) if (first == null || second == null) {
return 1.0; return 1.0;
}
// Create a string similarity service instance, to allow comparison // Create a string similarity service instance, to allow comparison
StringSimilarityService service = new StringSimilarityServiceImpl(new LevenshteinDistanceStrategy()); StringSimilarityService service = new StringSimilarityServiceImpl(new LevenshteinDistanceStrategy());

View File

@ -259,6 +259,9 @@ settings:
delayJoinLeaveMessages: true delayJoinLeaveMessages: true
# Do we need to add potion effect Blinding before login/register ? # Do we need to add potion effect Blinding before login/register ?
applyBlindEffect: false applyBlindEffect: false
# Do we need to prevent people to login without another case ?
# Xephi is registered, also Xephi can login, but not XEPHI/xephi/XePhI
preventOtherCase: false
ExternalBoardOptions: ExternalBoardOptions:
# MySQL column for the salt , needed for some forum/cms support # MySQL column for the salt , needed for some forum/cms support
mySQLColumnSalt: '' mySQLColumnSalt: ''

View File

@ -0,0 +1,135 @@
package fr.xephi.authme.command;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.command.CommandSender;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/**
* Test for {@link CommandHandler}.
*/
public class CommandHandlerTest {
private static Set<CommandDescription> commands;
private static CommandHandler handler;
@BeforeClass
public static void setUpCommandHandler() {
WrapperMock.createInstance();
CommandDescription authMeBase = createCommand(null, null, singletonList("authme"));
createCommand(PlayerPermission.LOGIN, authMeBase, singletonList("login"), newArgument("password", false));
createCommand(PlayerPermission.LOGIN, authMeBase, asList("register", "reg"),
newArgument("password", false), newArgument("confirmation", false));
CommandDescription testBase = createCommand(null, null, singletonList("test"), newArgument("test", true));
commands = new HashSet<>(asList(authMeBase, testBase));
handler = new CommandHandler(commands);
}
@Test
@Ignore
public void shouldForwardCommandToExecutable() {
// given
CommandSender sender = Mockito.mock(CommandSender.class);
given(sender.isOp()).willReturn(true);
String bukkitLabel = "authme";
String[] args = {"login", "password"};
// when
handler.processCommand(sender, bukkitLabel, args);
// then
final CommandDescription loginCmd = getChildWithLabel("login", getCommandWithLabel("authme", commands));
verify(sender, never()).sendMessage(anyString());
verify(loginCmd.getExecutableCommand()).executeCommand(
eq(sender), any(CommandParts.class), any(CommandParts.class));
}
@Test
@Ignore // TODO ljacqu Fix test --> command classes too tightly coupled at the moment
public void shouldRejectCommandWithTooManyArguments() {
// given
CommandSender sender = Mockito.mock(CommandSender.class);
given(sender.isOp()).willReturn(true);
String bukkitLabel = "authme";
String[] args = {"login", "password", "__unneededArgument__"};
// when
boolean result = handler.processCommand(sender, bukkitLabel, args);
// then
assertThat(result, equalTo(true));
assertSenderGotMessageContaining("help", sender);
}
private static CommandDescription createCommand(PlayerPermission permission, CommandDescription parent,
List<String> labels, CommandArgumentDescription... arguments) {
CommandDescription.CommandBuilder command = CommandDescription.builder()
.labels(labels)
.parent(parent)
.permissions(DefaultPermission.OP_ONLY, permission)
.description("Test")
.detailedDescription("Test command")
.executableCommand(mock(ExecutableCommand.class));
if (arguments != null && arguments.length > 0) {
for (CommandArgumentDescription argument : arguments) {
command.withArgument(argument.getLabel(), "Test description", argument.isOptional());
}
}
return command.build();
}
private static CommandArgumentDescription newArgument(String label, boolean isOptional) {
return new CommandArgumentDescription(label, "Test description", isOptional);
}
private void assertSenderGotMessageContaining(String text, CommandSender sender) {
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(sender).sendMessage(captor.capture());
assertThat(captor.getValue(), stringContainsInOrder(text));
}
private static CommandDescription getCommandWithLabel(String label, Collection<CommandDescription> commands) {
for (CommandDescription command : commands) {
if (command.getLabels().contains(label)) {
return command;
}
}
return null;
}
private static CommandDescription getChildWithLabel(String label, CommandDescription command) {
for (CommandDescription child : command.getChildren()) {
if (child.getLabels().contains(label)) {
return child;
}
}
return null;
}
}

View File

@ -1,11 +1,15 @@
package fr.xephi.authme.command; package fr.xephi.authme.command;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.WrapperMock; import fr.xephi.authme.util.WrapperMock;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -13,6 +17,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static fr.xephi.authme.permission.DefaultPermission.OP_ONLY;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@ -30,7 +35,7 @@ public class CommandInitializerTest {
*/ */
private static int MAX_ALLOWED_DEPTH = 1; private static int MAX_ALLOWED_DEPTH = 1;
private static List<CommandDescription> commands; private static Set<CommandDescription> commands;
@BeforeClass @BeforeClass
public static void initializeCommandManager() { public static void initializeCommandManager() {
@ -228,15 +233,51 @@ public class CommandInitializerTest {
walkThroughCommands(commands, noArgumentForParentChecker); walkThroughCommands(commands, noArgumentForParentChecker);
} }
/**
* Test that commands defined with the OP_ONLY default permission have at least one admin permission node.
*/
@Test
public void shouldNotHavePlayerPermissionIfDefaultsToOpOnly() {
// given
BiConsumer adminPermissionChecker = new BiConsumer() {
// The only exception to this check is the force login command, which should default to OP_ONLY
// but semantically it is a player permission
final List<String> forceLoginLabels = Arrays.asList("forcelogin", "login");
@Override
public void accept(CommandDescription command, int depth) {
CommandPermissions permissions = command.getCommandPermissions();
if (permissions != null && OP_ONLY.equals(permissions.getDefaultPermission())) {
if (!hasAdminNode(permissions) && !command.getLabels().equals(forceLoginLabels)) {
fail("The command with labels " + command.getLabels() + " has OP_ONLY default "
+ "permission but no permission node on admin level");
}
}
}
private boolean hasAdminNode(CommandPermissions permissions) {
for (PermissionNode node : permissions.getPermissionNodes()) {
if (node instanceof AdminPermission) {
return true;
}
}
return false;
}
};
// when/then
walkThroughCommands(commands, adminPermissionChecker);
}
// ------------ // ------------
// Helper methods // Helper methods
// ------------ // ------------
private static void walkThroughCommands(List<CommandDescription> commands, BiConsumer consumer) { private static void walkThroughCommands(Collection<CommandDescription> commands, BiConsumer consumer) {
walkThroughCommands(commands, consumer, 0); walkThroughCommands(commands, consumer, 0);
} }
private static void walkThroughCommands(List<CommandDescription> commands, BiConsumer consumer, int depth) { private static void walkThroughCommands(Collection<CommandDescription> commands, BiConsumer consumer, int depth) {
for (CommandDescription command : commands) { for (CommandDescription command : commands) {
consumer.accept(command, depth); consumer.accept(command, depth);
if (command.hasChildren()) { if (command.hasChildren()) {
@ -259,12 +300,12 @@ public class CommandInitializerTest {
} }
/** /**
* Get the absolute label that a command defines. Note: Assumes that only the passed command might have * Get the absolute binding that a command defines. Note: Assumes that only the passed command can have
* multiple labels; only considering the first label for all of the command's parents. * multiple labels; only considering the first label for all of the command's parents.
* *
* @param command The command to verify * @param command The command to process
* *
* @return The full command binding * @return List of all bindings that lead to the command
*/ */
private static List<String> getAbsoluteLabels(CommandDescription command) { private static List<String> getAbsoluteLabels(CommandDescription command) {
String parentPath = ""; String parentPath = "";

View File

@ -3,6 +3,7 @@ package fr.xephi.authme.command;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -27,7 +28,7 @@ public class CommandPartsTest {
@Test @Test
public void shouldPrintEmptyStringForNoArguments() { public void shouldPrintEmptyStringForNoArguments() {
// given // given
CommandParts parts = new CommandParts(); CommandParts parts = new CommandParts(Collections.EMPTY_LIST);
// when // when
String str = parts.toString(); String str = parts.toString();

View File

@ -15,6 +15,8 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -40,7 +42,7 @@ public class CaptchaCommandTest {
ExecutableCommand command = new CaptchaCommand(); ExecutableCommand command = new CaptchaCommand();
// when // when
boolean result = command.executeCommand(sender, new CommandParts(), new CommandParts()); boolean result = command.executeCommand(sender, new CommandParts(Collections.EMPTY_LIST), new CommandParts(Collections.EMPTY_LIST));
// then // then
assertThat(result, equalTo(true)); assertThat(result, equalTo(true));
@ -56,7 +58,7 @@ public class CaptchaCommandTest {
ExecutableCommand command = new CaptchaCommand(); ExecutableCommand command = new CaptchaCommand();
// when // when
boolean result = command.executeCommand(player, new CommandParts(), new CommandParts()); boolean result = command.executeCommand(player, new CommandParts(Collections.EMPTY_LIST), new CommandParts(Collections.EMPTY_LIST));
// then // then
assertThat(result, equalTo(true)); assertThat(result, equalTo(true));

View File

@ -18,6 +18,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -58,7 +59,7 @@ public class ChangePasswordCommandTest {
CommandParts arguments = mock(CommandParts.class); CommandParts arguments = mock(CommandParts.class);
// when // when
command.executeCommand(sender, new CommandParts(), arguments); command.executeCommand(sender, newParts(), arguments);
// then // then
verify(arguments, never()).get(anyInt()); verify(arguments, never()).get(anyInt());
@ -72,7 +73,7 @@ public class ChangePasswordCommandTest {
ChangePasswordCommand command = new ChangePasswordCommand(); ChangePasswordCommand command = new ChangePasswordCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts("pass")); command.executeCommand(sender, newParts(), new CommandParts("pass"));
// then // then
verify(messagesMock).send(sender, MessageKey.NOT_LOGGED_IN); verify(messagesMock).send(sender, MessageKey.NOT_LOGGED_IN);
@ -86,7 +87,7 @@ public class ChangePasswordCommandTest {
ChangePasswordCommand command = new ChangePasswordCommand(); ChangePasswordCommand command = new ChangePasswordCommand();
// when // when
command.executeCommand(sender, new CommandParts(), newParts("old123", "!pass")); command.executeCommand(sender, newParts(), newParts("old123", "!pass"));
// then // then
verify(messagesMock).send(sender, MessageKey.PASSWORD_MATCH_ERROR); verify(messagesMock).send(sender, MessageKey.PASSWORD_MATCH_ERROR);
@ -101,7 +102,7 @@ public class ChangePasswordCommandTest {
ChangePasswordCommand command = new ChangePasswordCommand(); ChangePasswordCommand command = new ChangePasswordCommand();
// when // when
command.executeCommand(sender, new CommandParts(), newParts("old_", "Tester")); command.executeCommand(sender, newParts(), newParts("old_", "Tester"));
// then // then
verify(messagesMock).send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR); verify(messagesMock).send(sender, MessageKey.PASSWORD_IS_USERNAME_ERROR);
@ -116,7 +117,7 @@ public class ChangePasswordCommandTest {
Settings.passwordMaxLength = 3; Settings.passwordMaxLength = 3;
// when // when
command.executeCommand(sender, new CommandParts(), newParts("12", "test")); command.executeCommand(sender, newParts(), newParts("12", "test"));
// then // then
verify(messagesMock).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); verify(messagesMock).send(sender, MessageKey.INVALID_PASSWORD_LENGTH);
@ -131,7 +132,7 @@ public class ChangePasswordCommandTest {
Settings.getPasswordMinLen = 7; Settings.getPasswordMinLen = 7;
// when // when
command.executeCommand(sender, new CommandParts(), newParts("oldverylongpassword", "tester")); command.executeCommand(sender, newParts(), newParts("oldverylongpassword", "tester"));
// then // then
verify(messagesMock).send(sender, MessageKey.INVALID_PASSWORD_LENGTH); verify(messagesMock).send(sender, MessageKey.INVALID_PASSWORD_LENGTH);
@ -146,7 +147,7 @@ public class ChangePasswordCommandTest {
Settings.unsafePasswords = asList("test", "abc123"); Settings.unsafePasswords = asList("test", "abc123");
// when // when
command.executeCommand(sender, new CommandParts(), newParts("oldpw", "abc123")); command.executeCommand(sender, newParts(), newParts("oldpw", "abc123"));
// then // then
verify(messagesMock).send(sender, MessageKey.PASSWORD_UNSAFE_ERROR); verify(messagesMock).send(sender, MessageKey.PASSWORD_UNSAFE_ERROR);
@ -160,7 +161,7 @@ public class ChangePasswordCommandTest {
ChangePasswordCommand command = new ChangePasswordCommand(); ChangePasswordCommand command = new ChangePasswordCommand();
// when // when
command.executeCommand(sender, new CommandParts(), newParts("abc123", "abc123")); command.executeCommand(sender, newParts(), newParts("abc123", "abc123"));
// then // then
verify(messagesMock, never()).send(eq(sender), any(MessageKey.class)); verify(messagesMock, never()).send(eq(sender), any(MessageKey.class));

View File

@ -11,6 +11,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -40,7 +41,7 @@ public class AddEmailCommandTest {
AddEmailCommand command = new AddEmailCommand(); AddEmailCommand command = new AddEmailCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
verify(authMeMock, never()).getManagement(); verify(authMeMock, never()).getManagement();
@ -53,11 +54,15 @@ public class AddEmailCommandTest {
AddEmailCommand command = new AddEmailCommand(); AddEmailCommand command = new AddEmailCommand();
// when // when
command.executeCommand(sender, new CommandParts(), command.executeCommand(sender, newParts(),
new CommandParts(Arrays.asList("mail@example", "other_example"))); new CommandParts(Arrays.asList("mail@example", "other_example")));
// then // then
verify(authMeMock).getManagement(); verify(authMeMock).getManagement();
verify(managementMock).performAddEmail(sender, "mail@example", "other_example"); verify(managementMock).performAddEmail(sender, "mail@example", "other_example");
} }
private static CommandParts newParts() {
return new CommandParts(new ArrayList<String>());
}
} }

View File

@ -11,6 +11,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -40,7 +41,7 @@ public class ChangeEmailCommandTest {
ChangeEmailCommand command = new ChangeEmailCommand(); ChangeEmailCommand command = new ChangeEmailCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
verify(authMeMock, never()).getManagement(); verify(authMeMock, never()).getManagement();
@ -53,11 +54,15 @@ public class ChangeEmailCommandTest {
ChangeEmailCommand command = new ChangeEmailCommand(); ChangeEmailCommand command = new ChangeEmailCommand();
// when // when
command.executeCommand(sender, new CommandParts(), command.executeCommand(sender, newParts(),
new CommandParts(Arrays.asList("new.mail@example.org", "old_mail@example.org"))); new CommandParts(Arrays.asList("new.mail@example.org", "old_mail@example.org")));
// then // then
verify(authMeMock).getManagement(); verify(authMeMock).getManagement();
verify(managementMock).performChangeEmail(sender, "new.mail@example.org", "old_mail@example.org"); verify(managementMock).performChangeEmail(sender, "new.mail@example.org", "old_mail@example.org");
} }
private static CommandParts newParts() {
return new CommandParts(new ArrayList<String>());
}
} }

View File

@ -9,6 +9,8 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.Collections;
/** /**
* Test for {@link RecoverEmailCommand}. * Test for {@link RecoverEmailCommand}.
*/ */
@ -27,7 +29,7 @@ public class RecoverEmailCommandTest {
RecoverEmailCommand command = new RecoverEmailCommand(); RecoverEmailCommand command = new RecoverEmailCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, new CommandParts(Collections.EMPTY_LIST), new CommandParts(Collections.EMPTY_LIST));
// then // then
} }

View File

@ -11,6 +11,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import static org.mockito.Matchers.*; import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -38,7 +40,7 @@ public class LoginCommandTest {
LoginCommand command = new LoginCommand(); LoginCommand command = new LoginCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
Mockito.verify(managementMock, never()).performLogin(any(Player.class), anyString(), anyBoolean()); Mockito.verify(managementMock, never()).performLogin(any(Player.class), anyString(), anyBoolean());
@ -51,7 +53,7 @@ public class LoginCommandTest {
LoginCommand command = new LoginCommand(); LoginCommand command = new LoginCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts("password")); command.executeCommand(sender, newParts(), new CommandParts("password"));
// then // then
Mockito.verify(managementMock).performLogin(eq(sender), eq("password"), eq(false)); Mockito.verify(managementMock).performLogin(eq(sender), eq("password"), eq(false));
@ -64,11 +66,15 @@ public class LoginCommandTest {
LoginCommand command = new LoginCommand(); LoginCommand command = new LoginCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
// TODO ljacqu 20151121: May make sense to handle null password in LoginCommand instead of forwarding the call // TODO ljacqu 20151121: May make sense to handle null password in LoginCommand instead of forwarding the call
String password = null; String password = null;
Mockito.verify(managementMock).performLogin(eq(sender), eq(password), eq(false)); Mockito.verify(managementMock).performLogin(eq(sender), eq(password), eq(false));
} }
private static CommandParts newParts() {
return new CommandParts(new ArrayList<String>());
}
} }

View File

@ -12,6 +12,8 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -40,7 +42,7 @@ public class LogoutCommandTest {
LogoutCommand command = new LogoutCommand(); LogoutCommand command = new LogoutCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, new CommandParts(new ArrayList<String>()), new CommandParts(new ArrayList<String>()));
// then // then
Mockito.verify(managementMock, never()).performLogout(any(Player.class)); Mockito.verify(managementMock, never()).performLogout(any(Player.class));
@ -53,7 +55,7 @@ public class LogoutCommandTest {
LogoutCommand command = new LogoutCommand(); LogoutCommand command = new LogoutCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts("password")); command.executeCommand(sender, new CommandParts(new ArrayList<String>()), new CommandParts("password"));
// then // then
Mockito.verify(managementMock).performLogout(sender); Mockito.verify(managementMock).performLogout(sender);

View File

@ -14,6 +14,8 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@ -48,7 +50,7 @@ public class RegisterCommandTest {
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
verify(sender).sendMessage(messageCaptor.capture()); verify(sender).sendMessage(messageCaptor.capture());
@ -63,7 +65,7 @@ public class RegisterCommandTest {
RegisterCommand command = new RegisterCommand(); RegisterCommand command = new RegisterCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts()); command.executeCommand(sender, newParts(), newParts());
// then // then
verify(messagesMock).send(sender, MessageKey.USAGE_REGISTER); verify(messagesMock).send(sender, MessageKey.USAGE_REGISTER);
@ -77,9 +79,13 @@ public class RegisterCommandTest {
RegisterCommand command = new RegisterCommand(); RegisterCommand command = new RegisterCommand();
// when // when
command.executeCommand(sender, new CommandParts(), new CommandParts("password")); command.executeCommand(sender, newParts(), new CommandParts("password"));
// then // then
verify(managementMock).performRegister(sender, "password", ""); verify(managementMock).performRegister(sender, "password", "");
} }
private static CommandParts newParts() {
return new CommandParts(new ArrayList<String>());
}
} }

View File

@ -3,10 +3,12 @@ package fr.xephi.authme.command.help;
import fr.xephi.authme.command.CommandDescription; import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.command.CommandParts; import fr.xephi.authme.command.CommandParts;
import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.command.executable.authme.RegisterCommand; import fr.xephi.authme.command.executable.authme.RegisterAdminCommand;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.util.ArrayList;
import static org.bukkit.ChatColor.BOLD; import static org.bukkit.ChatColor.BOLD;
import static org.bukkit.ChatColor.ITALIC; import static org.bukkit.ChatColor.ITALIC;
import static org.bukkit.ChatColor.WHITE; import static org.bukkit.ChatColor.WHITE;
@ -27,8 +29,7 @@ public class HelpSyntaxHelperTest {
.build(); .build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), "", false);
description, new CommandParts(), "", false);
// then // then
assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " [name]")); assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " [name]"));
@ -42,8 +43,7 @@ public class HelpSyntaxHelperTest {
.build(); .build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), null, false);
description, new CommandParts(), null, false);
// then // then
assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " <test>")); assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " <test>"));
@ -58,8 +58,7 @@ public class HelpSyntaxHelperTest {
.build(); .build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), "", false);
description, new CommandParts(), "", false);
// then // then
assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " [name]" + ITALIC + " <test>")); assertThat(result, equalTo(WHITE + "/authme register" + ITALIC + " [name]" + ITALIC + " <test>"));
@ -74,8 +73,7 @@ public class HelpSyntaxHelperTest {
.build(); .build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), "", true);
description, new CommandParts(), "", true);
// then // then
assertThat(result, equalTo(WHITE + "/authme " assertThat(result, equalTo(WHITE + "/authme "
@ -89,8 +87,7 @@ public class HelpSyntaxHelperTest {
CommandDescription description = getDescriptionBuilder().build(); CommandDescription description = getDescriptionBuilder().build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), null, true);
description, new CommandParts(), null, true);
// then // then
assertThat(result, equalTo(WHITE + "/authme " + YELLOW + BOLD + "register" + YELLOW)); assertThat(result, equalTo(WHITE + "/authme " + YELLOW + BOLD + "register" + YELLOW));
@ -104,33 +101,17 @@ public class HelpSyntaxHelperTest {
.build(); .build();
// when // when
String result = HelpSyntaxHelper.getCommandSyntax( String result = HelpSyntaxHelper.getCommandSyntax(description, newParts(), "alt", false);
description, new CommandParts(), "alt", false);
// then // then
assertThat(result, equalTo(WHITE + "/authme alt" + ITALIC + " [name]")); assertThat(result, equalTo(WHITE + "/authme alt" + ITALIC + " [name]"));
} }
@Test private static CommandParts newParts() {
public void shouldHighlightCommandWithAltLabelAndUnlimitedArguments() { // TODO ljacqu 20151204: Remove this method once CommandParts has been removed
// given return new CommandParts(new ArrayList<String>());
CommandDescription description = getDescriptionBuilder()
.withArgument("name", "", true)
.withArgument("test", "", false)
.noArgumentMaximum(true)
.build();
// when
String result = HelpSyntaxHelper.getCommandSyntax(
description, new CommandParts(), "test", true);
// then
assertThat(result, equalTo(WHITE + "/authme "
+ YELLOW + BOLD + "test"
+ YELLOW + ITALIC + " [name]" + ITALIC + " <test>" + ITALIC + " ..."));
} }
private static CommandDescription.CommandBuilder getDescriptionBuilder() { private static CommandDescription.CommandBuilder getDescriptionBuilder() {
CommandDescription base = CommandDescription.builder() CommandDescription base = CommandDescription.builder()
.labels("authme") .labels("authme")
@ -141,7 +122,7 @@ public class HelpSyntaxHelperTest {
.build(); .build();
return CommandDescription.builder() return CommandDescription.builder()
.executableCommand(Mockito.mock(RegisterCommand.class)) .executableCommand(Mockito.mock(RegisterAdminCommand.class))
.labels("register", "r") .labels("register", "r")
.description("Register a player") .description("Register a player")
.detailedDescription("Register the specified player with the specified password.") .detailedDescription("Register the specified player with the specified password.")

View File

@ -0,0 +1,102 @@
package fr.xephi.authme.util;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.empty;
/**
* Test for {@link CollectionUtils}.
*/
public class CollectionUtilsTest {
@Test
public void shouldGetFullList() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 0, 24);
// then
assertThat(result, equalTo(list));
}
@Test
public void shouldReturnEmptyListForZeroCount() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 2, 0);
// then
assertThat(result, empty());
}
@Test
public void shouldReturnEmptyListForTooHighStart() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 12, 2);
// then
assertThat(result, empty());
}
@Test
public void shouldReturnSubList() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 1, 3);
// then
assertThat(result, contains("1", "2", "3"));
}
@Test
public void shouldReturnTillEnd() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 2, 3);
// then
assertThat(result, contains("2", "3", "4"));
}
@Test
public void shouldRemoveFirstTwo() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, 2);
// then
assertThat(result, contains("2", "3", "4"));
}
@Test
public void shouldHandleNegativeStart() {
// given
List<String> list = Arrays.asList("test", "1", "2", "3", "4");
// when
List<String> result = CollectionUtils.getRange(list, -4);
// then
assertThat(result, equalTo(list));
}
}

3
src/tools/README.md Normal file
View File

@ -0,0 +1,3 @@
# About src/tools
This _tools_ folder provides helpers and extended tests useful during the development of AuthMe.
This folder is not included during the build of AuthMe.

View File

@ -0,0 +1,21 @@
## Bat Helpers
Collection of .bat files to quickly perform some frequent development tasks.
They allow you to quickly build the project and to move the generated JAR to
the plugins folder of your test server.
### Setup
1. Copy the files into a new, convenient directory
2. Open setvars.bat with a text editor and add the correct directories
3. Open `cmd` and navigate to your _bathelpers_ folder (`cd C:\path\the\folder`)
4. Type `list_files.bat` (Hint: Type `l` and hit Tab) to see the available tasks
### Example use case
1. After writing changes, `build_project` to build project
2. `move_plugin` moves the JAR file to the plugin folder
3. `run_server` to start the server with the fresh JAR
4. Problem detected, stop the server
5. Make a small change, use `quick_build` and `move_plugin` to update
6. Verify the change again on the server: `run_server`
All files start with a different letter, so you can conveniently type the
first letter and then complete with Tab.

View File

@ -0,0 +1,6 @@
: Analyze the project with Sonar (requires you install SonarQube)
if "%jarfile%" == "" (
call setvars.bat
)
mvn clean verify sonar:sonar -f "%pomfile%"

View File

@ -0,0 +1,6 @@
: Build the project normally
if "%jarfile%" == "" (
call setvars.bat
)
mvn clean install -f "%pomfile%" -B

View File

@ -0,0 +1,2 @@
: List all bat files in the directory
dir /B *.bat

View File

@ -0,0 +1,11 @@
: Moves the AuthMe JAR file to the plugins folder of the test server
: You will have to hit 'Y' to really replace it if it already exists
if "%jarfile%" == "" (
call setvars.bat
)
if exist %jarfile% (
xcopy %jarfile% %plugins%
) else (
echo Target file not found: '%jarfile%'
)

View File

@ -0,0 +1,6 @@
: Build quickly without cleaning or testing
if "%jarfile%" == "" (
call setvars.bat
)
mvn install -f "%pomfile%" -Dmaven.test.skip

View File

@ -0,0 +1,9 @@
: Start the Minecraft server
if "%jarfile%" == "" (
call setvars.bat
)
cd "%server%"
call java -Xmx1024M -Xms1024M -jar spigot_server.jar
cd "%batdir%"
dir /B *.bat

View File

@ -0,0 +1,14 @@
: The folder in which these .bat files are located
SET batdir=C:\your\path\AUTHME_DEV\bathelpers\
: The location of the generated JAR file
SET jarfile=C:\Users\yourname\IdeaProjects\AuthMeReloaded\target\AuthMe-5.1-SNAPSHOT.jar
: The location of the pom.xml file of the project
SET pomfile=C:\Users\yourname\IdeaProjects\AuthMeReloaded\pom.xml
: The folder in which the server is located
SET server=C:\your\path\AUTHME_DEV\spigot-server\
: The location of the plugins folder of the Minecraft server
SET plugins=%server%\plugins

View File

@ -0,0 +1,43 @@
<!-- AUTO-GENERATED FILE! Do not edit this directly -->
<!-- File auto-generated on Sat Dec 05 21:18:25 CET 2015. See permissions/permission_nodes.tpl.md -->
## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds.
- **authme.admin.*** Give access to all admin commands.
- **authme.admin.accounts** Administrator command to see all accounts associated with a user.
- **authme.admin.changemail** Administrator command to set or change the email address of a user.
- **authme.admin.changepassword** Administrator command to change the password of a user.
- **authme.admin.converter** Administrator command to convert old or other data to AuthMe data.
- **authme.admin.firstspawn** Administrator command to teleport to the first AuthMe spawn.
- **authme.admin.forcelogin** Administrator command to force-login an existing user.
- **authme.admin.getemail** Administrator command to get the email address of a user, if set.
- **authme.admin.getip** Administrator command to get the last known IP of a user.
- **authme.admin.lastlogin** Administrator command to see the last login date and time of a user.
- **authme.admin.purge** Administrator command to purge old user data.
- **authme.admin.purgebannedplayers** Administrator command to purge all data associated with banned players.
- **authme.admin.purgelastpos** Administrator command to purge the last position of a user.
- **authme.admin.register** Administrator command to register a new user.
- **authme.admin.reload** Administrator command to reload the plugin configuration.
- **authme.admin.setfirstspawn** Administrator command to set the first AuthMe spawn.
- **authme.admin.setspawn** Administrator command to set the AuthMe spawn.
- **authme.admin.spawn** Administrator command to teleport to the AuthMe spawn.
- **authme.admin.switchantibot** Administrator command to toggle the AntiBot protection status.
- **authme.admin.unregister** Administrator command to unregister an existing user.
- **authme.player.*** Permission to use all player (non-admin) commands.
- **authme.player.allow2accounts** Permission for users to allow two accounts.
- **authme.player.bypassantibot** Permission node to bypass AntiBot protection.
- **authme.player.bypassforcesurvival** Permission for users to bypass force-survival mode.
- **authme.player.canbeforced** Permission for users a login can be forced to.
- **authme.player.captcha** Command permission to use captcha.
- **authme.player.changepassword** Command permission to change the password.
- **authme.player.email.add** Command permission to add an email address.
- **authme.player.email.change** Command permission to change the email address.
- **authme.player.email.recover** Command permission to recover an account using it's email address.
- **authme.player.login** Command permission to login.
- **authme.player.logout** Command permission to logout.
- **authme.player.register** Command permission to register.
- **authme.player.seeotheraccounts** Permission for user to see other accounts.
- **authme.player.unregister** Command permission to unregister.
- **authme.player.vip** Permission node to identify VIP users.

View File

@ -0,0 +1,113 @@
package permissions;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.util.StringUtils;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Gatherer to generate up-to-date lists of the AuthMe permission nodes.
*/
public class PermissionNodesGatherer {
/** The folder in which the implementations of {@link PermissionNode} reside. */
private static final String PERMISSION_NODE_SOURCE_FOLDER =
"src/main/java/fr/xephi/authme/permission/";
/**
* Regular expression that should match the JavaDoc comment above an enum, <i>including</i>
* the name of the enum value. The first group (i.e. {@code \\1}) should be the JavaDoc description;
* the second group should contain the enum value.
*/
private static final Pattern JAVADOC_WITH_ENUM_PATTERN = Pattern.compile(
"/\\*\\*\\s+\\*" // Match starting '/**' and the '*' on the next line
+ "(.*?)\\s+\\*/" // Capture everything until we encounter '*/'
+ "\\s+([A-Z_]+)\\("); // Match the enum name (e.g. 'LOGIN'), until before the first '('
/**
* Return a sorted collection of all permission nodes.
*
* @return AuthMe permission nodes sorted alphabetically
*/
public Set<String> gatherNodes() {
Set<String> nodes = new TreeSet<>();
for (PermissionNode perm : PlayerPermission.values()) {
nodes.add(perm.getNode());
}
for (PermissionNode perm : AdminPermission.values()) {
nodes.add(perm.getNode());
}
return nodes;
}
/**
* Return a sorted collection of all permission nodes, including its JavaDoc description.
*
* @return Ordered map whose keys are the permission nodes and the values the associated JavaDoc
*/
public Map<String, String> gatherNodesWithJavaDoc() {
Map<String, String> result = new TreeMap<>();
addDescriptionsForClass(PlayerPermission.class, result);
addDescriptionsForClass(AdminPermission.class, result);
return result;
}
private <T extends Enum<T> & PermissionNode> void addDescriptionsForClass(Class<T> clazz,
Map<String, String> descriptions) {
String classSource = getSourceForClass(clazz);
Map<String, String> sourceDescriptions = extractJavaDocFromSource(classSource);
for (T perm : EnumSet.allOf(clazz)) {
String description = sourceDescriptions.get(perm.name());
if (description == null) {
System.out.println("Note: Could not retrieve description for "
+ clazz.getSimpleName() + "#" + perm.name());
description = "";
}
descriptions.put(perm.getNode(), description.trim());
}
}
private static Map<String, String> extractJavaDocFromSource(String source) {
Map<String, String> allMatches = new HashMap<>();
Matcher matcher = JAVADOC_WITH_ENUM_PATTERN.matcher(source);
while (matcher.find()) {
String description = matcher.group(1);
String enumValue = matcher.group(2);
allMatches.put(enumValue, description);
}
return allMatches;
}
/**
* Return the Java source code for the given implementation of {@link PermissionNode}.
*
* @param clazz The clazz to the get the source for
* @param <T> The concrete class
* @return Source code of the file
*/
private static <T extends Enum<T> & PermissionNode> String getSourceForClass(Class<T> clazz) {
String classFile = PERMISSION_NODE_SOURCE_FOLDER + clazz.getSimpleName() + ".java";
Charset cs = Charset.forName("utf-8");
try {
return StringUtils.join("\n",
Files.readAllLines(Paths.get(classFile), cs));
} catch (IOException e) {
throw new RuntimeException("Failed to get the source for class '" + clazz.getSimpleName() + "'");
}
}
}

View File

@ -0,0 +1,86 @@
package permissions;
import utils.ANewMap;
import utils.GeneratedFileWriter;
import utils.TagReplacer;
import utils.ToolsConstants;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
/**
* Class responsible for formatting a permissions node list and
* for writing it to a file if desired.
*/
public class PermissionsListWriter {
private static final String PERMISSIONS_OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "permission_nodes.md";
public static void main(String[] args) {
// Ask if result should be written to file
Scanner scanner = new Scanner(System.in);
System.out.println("Include description? [Enter 'n' for no]");
boolean includeDescription = !matches("n", scanner);
if (!includeDescription) {
outputSimpleList();
return;
}
System.out.println("Write to file? [Enter 'n' for console output]");
boolean writeToFile = !matches("n", scanner);
scanner.close();
if (writeToFile) {
generateAndWriteFile();
} else {
System.out.println(generatePermissionsList());
}
}
private static void generateAndWriteFile() {
final String permissionsTagValue = generatePermissionsList();
Map<String, Object> tags = ANewMap.<String, Object>with("permissions", permissionsTagValue).build();
GeneratedFileWriter.generateFileFromTemplate(
ToolsConstants.TOOLS_SOURCE_ROOT + "permissions/permission_nodes.tpl.md", PERMISSIONS_OUTPUT_FILE, tags);
System.out.println("Wrote to '" + PERMISSIONS_OUTPUT_FILE + "'");
System.out.println("Before committing, please verify the output!");
}
private static String generatePermissionsList() {
PermissionNodesGatherer gatherer = new PermissionNodesGatherer();
Map<String, String> permissions = gatherer.gatherNodesWithJavaDoc();
final String template = GeneratedFileWriter.readFromToolsFile("permissions/permission_node_entry.tpl.md");
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : permissions.entrySet()) {
Map<String, Object> tags = ANewMap.<String, Object>
with("node", entry.getKey())
.and("description", entry.getValue())
.build();
sb.append(TagReplacer.applyReplacements(template, tags));
}
return sb.toString();
}
private static void outputSimpleList() {
PermissionNodesGatherer gatherer = new PermissionNodesGatherer();
Set<String> nodes = gatherer.gatherNodes();
for (String node : nodes) {
System.out.println(node);
}
System.out.println();
System.out.println("Total: " + nodes.size());
}
private static boolean matches(String answer, Scanner sc) {
String userInput = sc.nextLine();
return answer.equalsIgnoreCase(userInput);
}
}

View File

@ -0,0 +1,2 @@
# About
Helper script to generate a page with an up-to-date list of permission nodes.

View File

@ -0,0 +1 @@
- **{node}** {description}

View File

@ -0,0 +1,7 @@
<!-- {gen_warning} -->
<!-- File auto-generated on {gen_date}. See permissions/permission_nodes.tpl.md -->
## AuthMe Permission Nodes
The following are the permission nodes that are currently supported by the latest dev builds.
{permissions}

View File

@ -0,0 +1,36 @@
package utils;
import java.util.HashMap;
import java.util.Map;
/**
* A map builder for the lazy.
* <p />
* Sample usage:
* <code>
* Map&lt;String, Integer> map = ANewMap
* .with("test", 123)
* .and("text", 938)
* .and("abc", 456)
* .build();
* </code>
*/
public class ANewMap<K, V> {
private Map<K, V> map = new HashMap<>();
public static <K, V> ANewMap<K, V> with(K key, V value) {
ANewMap<K, V> instance = new ANewMap<>();
return instance.and(key, value);
}
public ANewMap<K, V> and(K key, V value) {
map.put(key, value);
return this;
}
public Map<K, V> build() {
return map;
}
}

View File

@ -0,0 +1,47 @@
package utils;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
/**
* Utility class for writing a generated file with a timestamp.
*/
public final class GeneratedFileWriter {
private final static Charset CHARSET = Charset.forName("utf-8");
private GeneratedFileWriter() {
}
public static void generateFileFromTemplate(String templateFile, String destinationFile, Map<String, Object> tags) {
String template = readFromFile(templateFile);
String result = TagReplacer.applyReplacements(template, tags);
writeToFile(destinationFile, result);
}
private static void writeToFile(String outputFile, String contents) {
try {
Files.write(Paths.get(outputFile), contents.getBytes());
} catch (IOException e) {
throw new RuntimeException("Failed to write to file '" + outputFile + "'", e);
}
}
public static String readFromFile(String file) {
try {
return new String(Files.readAllBytes(Paths.get(file)), CHARSET);
} catch (IOException e) {
throw new RuntimeException("Could not read from file '" + file + "'", e);
}
}
public static String readFromToolsFile(String file) {
return readFromFile(ToolsConstants.TOOLS_SOURCE_ROOT + file);
}
}

View File

@ -0,0 +1,46 @@
package utils;
import java.util.Date;
import java.util.Map;
/**
* Class responsible for replacing template tags to actual content.
* For all files, the following tags are defined:
* <ul>
* <li>{gen_date} the generation date</li>
* <li>{gen_warning} - warning not to edit the generated file directly</li>
* </ul>
*/
public class TagReplacer {
/**
* Replace a template with default tags and custom ones supplied by a map.
*
* @param template The template to process
* @param tags Map with additional tags, e.g. a map entry with key "foo" and value "bar" will replace
* any occurrences of "{foo}" to "bar".
* @return The filled template
*/
public static String applyReplacements(String template, Map<String, Object> tags) {
String result = template;
for (Map.Entry<String, Object> tagRule : tags.entrySet()) {
result = result.replace("{" + tagRule.getKey() + "}", tagRule.getValue().toString());
}
return applyReplacements(result);
}
/**
* Apply the default tag replacements.
*
* @param template The template to process
* @return The filled template
*/
public static String applyReplacements(String template) {
return template
.replace("{gen_date}", new Date().toString())
.replace("{gen_warning}", "AUTO-GENERATED FILE! Do not edit this directly");
}
}

View File

@ -0,0 +1,17 @@
package utils;
/**
* Constants for the src/tools folder.
*/
public final class ToolsConstants {
private ToolsConstants() {
}
public static final String MAIN_SOURCE_ROOT = "src/main/java/";
public static final String TOOLS_SOURCE_ROOT = "src/tools/";
public static final String DOCS_FOLDER = TOOLS_SOURCE_ROOT + "docs/";
}