#347 Test that all read properties exist as Property field
- Create consistency test to verify that all properties in config.yml are defined as a Property field in a SettingsClass implementation (currently fails) - Add some missing properties - Minor: convert tabs to spaces
This commit is contained in:
parent
0603243c86
commit
88629702f5
@ -30,6 +30,10 @@ public class EmailSettings implements SettingsClass {
|
|||||||
public static final Property<String> MAIL_PASSWORD =
|
public static final Property<String> MAIL_PASSWORD =
|
||||||
newProperty(STRING, "Email.mailPassword", "");
|
newProperty(STRING, "Email.mailPassword", "");
|
||||||
|
|
||||||
|
@Comment("Custom sender name, replacing the mailAccount name in the email")
|
||||||
|
public static final Property<String> MAIL_SENDER_NAME =
|
||||||
|
newProperty("Email.mailSenderName", "");
|
||||||
|
|
||||||
@Comment("Recovery password length")
|
@Comment("Recovery password length")
|
||||||
public static final Property<Integer> RECOVERY_PASSWORD_LENGTH =
|
public static final Property<Integer> RECOVERY_PASSWORD_LENGTH =
|
||||||
newProperty(INTEGER, "Email.RecoveryPasswordLength", 8);
|
newProperty(INTEGER, "Email.RecoveryPasswordLength", 8);
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
package fr.xephi.authme.settings.custom;
|
||||||
|
|
||||||
|
import fr.xephi.authme.settings.domain.Comment;
|
||||||
|
import fr.xephi.authme.settings.domain.Property;
|
||||||
|
import fr.xephi.authme.settings.domain.SettingsClass;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.settings.domain.Property.newProperty;
|
||||||
|
|
||||||
|
public class PluginSettings implements SettingsClass {
|
||||||
|
|
||||||
|
@Comment("The name shown in the help messages")
|
||||||
|
public static final Property<String> HELP_HEADER =
|
||||||
|
newProperty("settings.helpHeader", "AuthMeReloaded");
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Do you want to enable the session feature?",
|
||||||
|
"If enabled, when a player authenticates successfully,",
|
||||||
|
"his IP and his nickname is saved.",
|
||||||
|
"The next time the player joins the server, if his IP",
|
||||||
|
"is the same as last time and the timeout hasn't",
|
||||||
|
"expired, he will not need to authenticate."
|
||||||
|
})
|
||||||
|
public static final Property<Boolean> SESSIONS_ENABLED =
|
||||||
|
newProperty("settings.sessions.enabled", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"After how many minutes should a session expire?",
|
||||||
|
"0 for unlimited time (Very dangerous, use it at your own risk!)",
|
||||||
|
"Remember that sessions will end only after the timeout, and",
|
||||||
|
"if the player's IP has changed but the timeout hasn't expired,",
|
||||||
|
"the player will be kicked from the server due to invalid session"
|
||||||
|
})
|
||||||
|
public static final Property<Integer> SESSIONS_TIMEOUT =
|
||||||
|
newProperty("settings.sessions.timeout", 10);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Should the session expire if the player tries to log in with",
|
||||||
|
"another IP address?"
|
||||||
|
})
|
||||||
|
public static final Property<Boolean> SESSIONS_EXPIRE_ON_IP_CHANGE =
|
||||||
|
newProperty("settings.sessions.sessionExpireOnIpChange", true);
|
||||||
|
|
||||||
|
private PluginSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
package fr.xephi.authme.settings.custom;
|
||||||
|
|
||||||
|
import fr.xephi.authme.settings.domain.Comment;
|
||||||
|
import fr.xephi.authme.settings.domain.Property;
|
||||||
|
import fr.xephi.authme.settings.domain.PropertyType;
|
||||||
|
import fr.xephi.authme.settings.domain.SettingsClass;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.xephi.authme.settings.domain.Property.newProperty;
|
||||||
|
|
||||||
|
public class RestrictionSettings implements SettingsClass {
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Can not authenticated players chat and see the chat log?",
|
||||||
|
"Keep in mind that this feature also blocks all commands not",
|
||||||
|
"listed in the list below."})
|
||||||
|
public static final Property<Boolean> ALLOW_CHAT =
|
||||||
|
newProperty("settings.restrictions.allowChat", false);
|
||||||
|
|
||||||
|
@Comment("Allowed commands for unauthenticated players")
|
||||||
|
public static final Property<List<String>> ALLOW_COMMANDS =
|
||||||
|
newProperty(PropertyType.STRING_LIST, "settings.restrictions.allowCommands",
|
||||||
|
"login", "register", "l", "reg", "email", "captcha");
|
||||||
|
|
||||||
|
@Comment("Max number of allowed registrations per IP")
|
||||||
|
// TODO ljacqu 20160109: If 0 == unlimited, add this fact ot the comment
|
||||||
|
public static final Property<Integer> MAX_REGISTRATION_PER_IP =
|
||||||
|
newProperty("settings.restrictions.maxRegPerIp", 1);
|
||||||
|
|
||||||
|
@Comment("Minimum allowed username length")
|
||||||
|
public static final Property<Integer> MIN_NICKNAME_LENGTH =
|
||||||
|
newProperty("settings.restrictions.minNicknameLength", 4);
|
||||||
|
|
||||||
|
@Comment("Maximum allowed username length")
|
||||||
|
public static final Property<Integer> MAX_NICKNAME_LENGTH =
|
||||||
|
newProperty("settings.restrictions.maxNicknameLength", 16);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"When this setting is enabled, online players can't be kicked out",
|
||||||
|
"due to \"Logged in from another Location\"",
|
||||||
|
"This setting will prevent potential security exploits."})
|
||||||
|
public static final Property<Boolean> FORCE_SINGLE_SESSION =
|
||||||
|
newProperty("settings.restrictions.ForceSingleSession", true);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"If enabled, every player will be teleported to the world spawnpoint",
|
||||||
|
"after successful authentication.",
|
||||||
|
"The quit location of the player will be overwritten.",
|
||||||
|
"This is different from \"teleportUnAuthedToSpawn\" that teleport player",
|
||||||
|
"back to his quit location after the authentication."})
|
||||||
|
public static final Property<Boolean> FORCE_SPAWN_LOCATION_AFTER_LOGIN =
|
||||||
|
newProperty("settings.restrictions.ForceSpawnLocOnJoinEnabled", false);
|
||||||
|
|
||||||
|
@Comment("This option will save the quit location of the players.")
|
||||||
|
public static final Property<Boolean> SAVE_QUIT_LOCATION =
|
||||||
|
newProperty("settings.restrictions.SaveQuitLocation", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"To activate the restricted user feature you need",
|
||||||
|
"to enable this option and configure the AllowedRestrctedUser field."})
|
||||||
|
public static final Property<Boolean> ENABLE_RESTRICTED_USERS =
|
||||||
|
newProperty("settings.restrictions.AllowRestrictedUser", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"The restricted user feature will kick players listed below",
|
||||||
|
"if they don't match the defined IP address.",
|
||||||
|
"Example:",
|
||||||
|
" AllowedRestrictedUser:",
|
||||||
|
" - playername;127.0.0.1"})
|
||||||
|
public static final Property<List<String>> ALLOWED_RESTRICTED_USERS =
|
||||||
|
newProperty(PropertyType.STRING_LIST, "settings.restrictions.AllowedRestrictedUser");
|
||||||
|
|
||||||
|
@Comment("Should unregistered players be kicked immediately?")
|
||||||
|
public static final Property<Boolean> KICK_NON_REGISTERED =
|
||||||
|
newProperty("settings.restrictions.kickNonRegistered", false);
|
||||||
|
|
||||||
|
@Comment("Should players be kicked on wrong password?")
|
||||||
|
public static final Property<Boolean> KICK_ON_WRONG_PASSWORD =
|
||||||
|
newProperty("settings.restrictions.kickOnWrongPassword", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Should not logged in players be teleported to the spawn?",
|
||||||
|
"After the authentication they will be teleported back to",
|
||||||
|
"their normal position."})
|
||||||
|
public static final Property<Boolean> TELEPORT_UNAUTHED_TO_SPAWN =
|
||||||
|
newProperty("settings.restrictions.teleportUnAuthedToSpawn", false);
|
||||||
|
|
||||||
|
@Comment("Can unregistered players walk around?")
|
||||||
|
public static final Property<Boolean> ALLOW_UNAUTHED_MOVEMENT =
|
||||||
|
newProperty("settings.restrictions.allowMovement", false);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Should not authenticated players have speed = 0?",
|
||||||
|
"This will reset the fly/walk speed to default value after the login."})
|
||||||
|
public static final Property<Boolean> REMOVE_SPEED =
|
||||||
|
newProperty("settings.restrictions.removeSpeed", true);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"After how many seconds should players who fail to login or register",
|
||||||
|
"be kicked? Set to 0 to disable."})
|
||||||
|
public static final Property<Integer> TIMEOUT =
|
||||||
|
newProperty("settings.restrictions.timeout", 30);
|
||||||
|
|
||||||
|
@Comment("Regex syntax of allowed characters in the player name.")
|
||||||
|
public static final Property<String> ALLOWED_NICKNAME_CHARACTERS =
|
||||||
|
newProperty("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*");
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"How far can unregistered players walk?",
|
||||||
|
"Set to 0 for unlimited radius"
|
||||||
|
})
|
||||||
|
public static final Property<Integer> ALLOWED_MOVEMENT_RADIUS =
|
||||||
|
newProperty("settings.restrictions.allowedMovementRadius", 100);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Enable double check of password when you register",
|
||||||
|
"when it's true, registration requires that kind of command:",
|
||||||
|
"/register <password> <confirmPassword>"})
|
||||||
|
public static final Property<Boolean> ENABLE_PASSWORD_CONFIRMATION =
|
||||||
|
newProperty("settings.restrictions.enablePasswordConfirmation", true);
|
||||||
|
|
||||||
|
@Comment("Should we protect the player inventory before logging in?")
|
||||||
|
public static final Property<Boolean> PROTECT_INVENTORY_BEFORE_LOGIN =
|
||||||
|
newProperty("settings.restrictions.ProtectInventoryBeforeLogIn", true);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Should we display all other accounts from a player when he joins?",
|
||||||
|
"permission: /authme.admin.accounts"})
|
||||||
|
public static final Property<Boolean> DISPLAY_OTHER_ACCOUNTS =
|
||||||
|
newProperty("settings.restrictions.displayOtherAccounts", true);
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"WorldNames where we need to force the spawn location for ForceSpawnLocOnJoinEnabled",
|
||||||
|
"Case-sensitive!"})
|
||||||
|
public static final Property<List<String>> FORCE_SPAWN_ON_WORLDS =
|
||||||
|
newProperty(PropertyType.STRING_LIST, "settings.restrictions.ForceSpawnOnTheseWorlds",
|
||||||
|
"world", "world_nether", "world_the_end");
|
||||||
|
|
||||||
|
@Comment("Ban ip when the ip is not the ip registered in database")
|
||||||
|
public static final Property<Boolean> BAN_UNKNOWN_IP =
|
||||||
|
newProperty("settings.restrictions.banUnsafedIP", false);
|
||||||
|
|
||||||
|
private RestrictionSettings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -18,7 +18,8 @@ final class SettingsFieldRetriever {
|
|||||||
|
|
||||||
/** The classes to scan for properties. */
|
/** The classes to scan for properties. */
|
||||||
private static final List<Class<? extends SettingsClass>> CONFIGURATION_CLASSES = Arrays.asList(
|
private static final List<Class<? extends SettingsClass>> CONFIGURATION_CLASSES = Arrays.asList(
|
||||||
ConverterSettings.class, DatabaseSettings.class, EmailSettings.class, HooksSettings.class,
|
ConverterSettings.class, PluginSettings.class, RestrictionSettings.class,
|
||||||
|
DatabaseSettings.class, EmailSettings.class, HooksSettings.class,
|
||||||
ProtectionSettings.class, PurgeSettings.class, SecuritySettings.class);
|
ProtectionSettings.class, PurgeSettings.class, SecuritySettings.class);
|
||||||
|
|
||||||
private SettingsFieldRetriever() {
|
private SettingsFieldRetriever() {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import java.util.TreeMap;
|
|||||||
*/
|
*/
|
||||||
public class PropertyMap {
|
public class PropertyMap {
|
||||||
|
|
||||||
private Map<Property<?>, String[]> propertyMap;
|
private Map<Property<?>, String[]> map;
|
||||||
private PropertyMapComparator comparator;
|
private PropertyMapComparator comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,7 +22,7 @@ public class PropertyMap {
|
|||||||
*/
|
*/
|
||||||
public PropertyMap() {
|
public PropertyMap() {
|
||||||
comparator = new PropertyMapComparator();
|
comparator = new PropertyMapComparator();
|
||||||
propertyMap = new TreeMap<>(comparator);
|
map = new TreeMap<>(comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +33,7 @@ public class PropertyMap {
|
|||||||
*/
|
*/
|
||||||
public void put(Property property, String[] comments) {
|
public void put(Property property, String[] comments) {
|
||||||
comparator.add(property);
|
comparator.add(property);
|
||||||
propertyMap.put(property, comments);
|
map.put(property, comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +42,7 @@ public class PropertyMap {
|
|||||||
* @return The entry set
|
* @return The entry set
|
||||||
*/
|
*/
|
||||||
public Set<Map.Entry<Property<?>, String[]>> entrySet() {
|
public Set<Map.Entry<Property<?>, String[]>> entrySet() {
|
||||||
return propertyMap.entrySet();
|
return map.entrySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +51,16 @@ public class PropertyMap {
|
|||||||
* @return The key set
|
* @return The key set
|
||||||
*/
|
*/
|
||||||
public Set<Property<?>> keySet() {
|
public Set<Property<?>> keySet() {
|
||||||
return propertyMap.keySet();
|
return map.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the size of the map.
|
||||||
|
*
|
||||||
|
* @return The size
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -340,8 +340,6 @@ Email:
|
|||||||
RecoveryPasswordLength: 8
|
RecoveryPasswordLength: 8
|
||||||
# Email subject of password get
|
# Email subject of password get
|
||||||
mailSubject: 'Your new AuthMe Password'
|
mailSubject: 'Your new AuthMe Password'
|
||||||
# Email text here
|
|
||||||
mailText: 'Dear <playername>, <br /><br /> This is your new AuthMe password for the server <br /><br /> <servername> : <br /><br /> <generatedpass><br /><image><br />Do not forget to change password after login! <br /> /changepassword <generatedpass> newPassword'
|
|
||||||
# Like maxRegPerIp but with email
|
# Like maxRegPerIp but with email
|
||||||
maxRegPerEmail: 1
|
maxRegPerEmail: 1
|
||||||
# Recall players to add an email?
|
# Recall players to add an email?
|
||||||
|
|||||||
@ -1,14 +1,24 @@
|
|||||||
package fr.xephi.authme.settings.custom;
|
package fr.xephi.authme.settings.custom;
|
||||||
|
|
||||||
|
import fr.xephi.authme.settings.domain.Property;
|
||||||
|
import fr.xephi.authme.settings.propertymap.PropertyMap;
|
||||||
|
import fr.xephi.authme.util.StringUtils;
|
||||||
|
import org.bukkit.configuration.MemorySection;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
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.junit.Assume.assumeThat;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link NewSetting} and the project's config.yml,
|
* Test for {@link NewSetting} and the project's config.yml,
|
||||||
@ -16,14 +26,15 @@ import static org.junit.Assume.assumeThat;
|
|||||||
*/
|
*/
|
||||||
public class ConfigFileConsistencyTest {
|
public class ConfigFileConsistencyTest {
|
||||||
|
|
||||||
|
/** The file name of the project's sample config file. */
|
||||||
|
private static final String CONFIG_FILE = "/config.yml";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldHaveAllConfigs() throws IOException {
|
public void shouldHaveAllConfigs() throws IOException {
|
||||||
URL url = this.getClass().getResource("/config.yml");
|
|
||||||
File configFile = new File(url.getFile());
|
|
||||||
|
|
||||||
// given
|
// given
|
||||||
assumeThat(configFile.exists(), equalTo(true));
|
URL url = this.getClass().getResource(CONFIG_FILE);
|
||||||
NewSetting settings = new NewSetting(configFile);
|
File configFile = new File(url.getFile());
|
||||||
|
NewSetting settings = new NewSetting(YamlConfiguration.loadConfiguration(configFile), new File("bogus"), null);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
boolean result = settings.containsAllSettings(SettingsFieldRetriever.getAllPropertyFields());
|
boolean result = settings.containsAllSettings(SettingsFieldRetriever.getAllPropertyFields());
|
||||||
@ -32,4 +43,38 @@ public class ConfigFileConsistencyTest {
|
|||||||
assertThat(result, equalTo(true));
|
assertThat(result, equalTo(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotHaveUnknownConfigs() {
|
||||||
|
// given
|
||||||
|
URL url = this.getClass().getResource(CONFIG_FILE);
|
||||||
|
File configFile = new File(url.getFile());
|
||||||
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
|
||||||
|
Map<String, Object> allReadProperties = configuration.getValues(true);
|
||||||
|
Set<String> knownKeys = getAllKnownPropertyPaths();
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<String> unknownPaths = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, Object> entry : allReadProperties.entrySet()) {
|
||||||
|
// The value being a MemorySection means it's a parent node
|
||||||
|
if (!(entry.getValue() instanceof MemorySection) && !knownKeys.contains(entry.getKey())) {
|
||||||
|
unknownPaths.add(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// then
|
||||||
|
if (!unknownPaths.isEmpty()) {
|
||||||
|
fail("Found " + unknownPaths.size() + " unknown property paths in the project's config.yml: \n- "
|
||||||
|
+ StringUtils.join("\n- ", unknownPaths));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> getAllKnownPropertyPaths() {
|
||||||
|
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
|
||||||
|
Set<String> paths = new HashSet<>(propertyMap.size());
|
||||||
|
for (Property<?> property : propertyMap.keySet()) {
|
||||||
|
paths.add(property.getPath());
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user