Merge master into 477-lastlogin-timestamp

Conflicts:
    - Settings.java
This commit is contained in:
ljacqu 2016-02-13 20:03:06 +01:00
commit 7b26dd25a0
81 changed files with 1948 additions and 1681 deletions

View File

@ -2,27 +2,25 @@
<p align="center"><strong>The most used authentication plugin for CraftBukkit/Spigot!</strong></p> <p align="center"><strong>The most used authentication plugin for CraftBukkit/Spigot!</strong></p>
<hr> <hr>
####Development history:
[![Gource AuthMe History Video](http://img.youtube.com/vi/hJRzNfYyd9k/hqdefault.jpg)](https://www.youtube.com/watch?v=hJRzNfYyd9k)
#####Development tools: #####Development tools:
- DEVELOPMENT TEAM REPO (<strong>please send PRs here!</strong>): <a href="https://github.com/AuthMe-Team/AuthMeReloaded">Github Development Page</a> - DEVELOPMENT TEAM REPO (<strong>please send PRs here!</strong>): <a href="https://github.com/AuthMe-Team/AuthMeReloaded">Github Development Page</a>
- Developers ChatRoom: [![Join the chat at https://gitter.im/Xephi/AuthMeReloaded](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - Developers ChatRoom: [![Join the chat at https://gitter.im/Xephi/AuthMeReloaded](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Xephi/AuthMeReloaded?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- Build status: [![Build Status](https://travis-ci.org/Xephi/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/Xephi/AuthMeReloaded) [![Dependency Status](https://www.versioneye.com/user/projects/55bab9e8653762002000190a/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55bab9e8653762002000190a) - Build Server (<strong>DEVELOPMENT BUILDS</strong>): <a href="http://ci.xephi.fr/job/AuthMeReloaded">Xephi's Jenkins</a>
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/Xephi/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/Xephi/AuthMeReloaded) - Build status: [![Build Status](https://travis-ci.org/AuthMe-Team/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/AuthMe-Team/AuthMeReloaded) [![Dependency Status](https://www.versioneye.com/user/projects/55bab9e8653762002000190a/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55bab9e8653762002000190a)
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe-Team/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/AuthMe-Team/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/AuthMe-Team/AuthMeReloaded)
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe-Team/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
- JitPack (just in case): [![](https://jitpack.io/v/AuthMe-Team/AuthMeReloaded.svg)](https://jitpack.io/#AuthMe-Team/AuthMeReloaded)
- Code Coverage: [![Coverage Status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master) - Code Coverage: [![Coverage Status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)
- Issue Tracking : [![Stories in Ready](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=ready&title=Ready)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in Bugs](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=bugs&title=Bugs)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in In%20Progress](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=in%20progress&title=In%20Progress)](https://waffle.io/Xephi/AuthMeReloaded) - Issue Tracking : [![Stories in Ready](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=ready&title=Ready)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in Bugs](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=bugs&title=Bugs)](https://waffle.io/Xephi/AuthMeReloaded) [![Stories in In%20Progress](https://badge.waffle.io/Xephi/AuthMeReloaded.png?label=in%20progress&title=In%20Progress)](https://waffle.io/Xephi/AuthMeReloaded)
- Build Server (<strong>DEVELOPMENT BUILDS</strong>): <a href="http://ci.xephi.fr/job/AuthMeReloaded">Xephi's Jenkins</a> - JavaDoc: <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">AuthMe Javadoc</a>
- JavaDocs: <a href="http://ci.xephi.fr/job/AuthMeReloaded/javadoc/">AuthMe Javadoc</a>
- Maven Repo: <a href="http://ci.xephi.fr/plugin/repository/everything/">AuthMe Repo</a> - Maven Repo: <a href="http://ci.xephi.fr/plugin/repository/everything/">AuthMe Repo</a>
@ -36,6 +34,9 @@ McStats: http://mcstats.org/plugin/AuthMe
<img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png"> <img src="http://i.mcstats.org/AuthMe/Version+Demographics.borderless.png">
#####Development history:
[![Gource AuthMe History Video](http://img.youtube.com/vi/hJRzNfYyd9k/hqdefault.jpg)](https://www.youtube.com/watch?v=hJRzNfYyd9k)
<hr> <hr>
#####Compiling Requirements: #####Compiling Requirements:
@ -83,6 +84,7 @@ typing commands or using the inventory. It can also kick players with uncommonly
<li>Xenforo: XFBCRYPT</li> <li>Xenforo: XFBCRYPT</li>
<li>MyBB: MYBB</li> <li>MyBB: MYBB</li>
<li>IPB3: IPB3</li> <li>IPB3: IPB3</li>
<li>IPB4: IPB4</li>
<li>PhpFusion: PHPFUSION</li> <li>PhpFusion: PHPFUSION</li>
<li>Joomla: JOOMLA</li> <li>Joomla: JOOMLA</li>
<li>WBB3: WBB3*</li> <li>WBB3: WBB3*</li>

View File

@ -8,8 +8,9 @@ test:
override: override:
- mvn clean install -B - mvn clean install -B
post: post:
- cp ./target/AuthMe*.jar $CIRCLE_ARTIFACTS - cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT.jar $CIRCLE_ARTIFACTS/AuthMe.jar - cp ./target/AuthMe-*-SNAPSHOT-legacy.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT-spigot.jar $CIRCLE_ARTIFACTS/AuthMe.jar
notify: notify:
webhooks: webhooks:
- url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf - url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf

1446
pom.xml

File diff suppressed because it is too large Load Diff

View File

@ -421,7 +421,9 @@ settings:
# Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player
broadcastWelcomeMessage: false broadcastWelcomeMessage: false
# Do we need to delay the join/leave message to be displayed only when the player is authenticated ? # Do we need to delay the join/leave message to be displayed only when the player is authenticated ?
delayJoinLeaveMessages: true delayJoinMessage: false
removeJoinMessage: false
removeLeaveMessage: false
# 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
ExternalBoardOptions: ExternalBoardOptions:

View File

@ -0,0 +1,52 @@
<!--
This is a demo page for AuthMe website integration.
See integration.php for the PHP code you need.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>AuthMe Integration Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php
error_reporting(E_ALL);
$user = get_from_post_or_empty('username');
$pass = get_from_post_or_empty('password');
$was_successful = false;
if ($user && $pass) {
require_once('integration.php');
if (authme_check_password($user, $pass)) {
printf('<h1>Hello, %s!</h1>', htmlspecialchars($user));
echo 'Successful login. Nice to have you back!'
. '<br /><a href="form.php">Back to form</a>';
$was_successful = true;
} else {
echo '<h1>Error</h1> Invalid username or password.';
}
}
if (!$was_successful) {
echo '<h1>Login sample</h1>
This is a demo form for AuthMe website integration. Enter your AuthMe login details
into the following form to test it.
<form method="post">
<table>
<tr><td>Name</td><td><input type="text" value="' . htmlspecialchars($user) . '" name="username" /></td></tr>
<tr><td>Pass</td><td><input type="password" value="' . htmlspecialchars($pass) . '" name="password" /></td></tr>
<tr><td colspan="2"><input type="submit" value=" Log in " />
</table>
</form>';
}
function get_from_post_or_empty($index_name) {
return trim(
filter_input(INPUT_POST, $index_name, FILTER_UNSAFE_RAW, FILTER_REQUIRE_SCALAR | FILTER_FLAG_STRIP_LOW)
?: '');
}
?>
</body>
</html>

View File

@ -0,0 +1,67 @@
<?php
/*****************************************************************************
* AuthMe website integration logic *
* -------------------------------- *
* Check with authme_check_password() whether the received username and *
* password match the AuthMe MySQL database. Don't forget to adjust the *
* database info in authme_get_hash(). *
* *
* Source: https://github.com/AuthMe-Team/AuthMeReloaded/ *
*****************************************************************************/
/**
* Entry point function to check supplied credentials against the AuthMe database.
*
* @param string $username the username
* @param string $password the password
* @return bool true iff the data is correct, false otherwise
*/
function authme_check_password($username, $password) {
if (is_scalar($username) && is_scalar($password)) {
$hash = authme_get_hash($username);
if ($hash) {
return authme_check_hash($password, $hash);
}
}
return false;
}
/**
* Retrieves the hash associated with the given user from the database.
*
* @param string $username the username whose hash should be retrieved
* @return string|null the hash, or null if unavailable (e.g. username doesn't exist)
*/
function authme_get_hash($username) {
// Add here your database host, username, password and database name
$mysqli = new mysqli('HOST', 'USER', 'PWD', 'DB');
$authme_table = 'authme';
if (mysqli_connect_error()) {
printf('Could not connect to AuthMe database. Errno: %d, error: "%s"',
mysqli_connect_errno(), mysqli_connect_error());
} else {
$stmt = $mysqli->prepare("SELECT password FROM $authme_table WHERE username = ?");
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->bind_result($password);
if ($stmt->fetch()) {
return $password;
}
}
return null;
}
/**
* Checks the given clear-text password against the hash.
*
* @param string $password the clear-text password to check
* @param string $hash the hash to check the password against
* @return bool true iff the password matches the hash, false otherwise
*/
function authme_check_hash($password, $hash) {
// $SHA$salt$hash, where hash := sha256(sha256(password) . salt)
$parts = explode('$', $hash);
return count($parts) === 4
&& $parts[3] === hash('sha256', hash('sha256', $password) . $parts[2]);
}

View File

@ -61,6 +61,7 @@ import fr.xephi.authme.listener.AuthMePlayerListener16;
import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMePlayerListener18;
import fr.xephi.authme.listener.AuthMeServerListener; import fr.xephi.authme.listener.AuthMeServerListener;
import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter;
import fr.xephi.authme.listener.AuthMeTablistPacketAdapter;
import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.output.ConsoleFilter; import fr.xephi.authme.output.ConsoleFilter;
import fr.xephi.authme.output.Log4JFilter; import fr.xephi.authme.output.Log4JFilter;
@ -133,6 +134,7 @@ public class AuthMe extends JavaPlugin {
public CombatTagPlus combatTagPlus; public CombatTagPlus combatTagPlus;
public AuthMeInventoryPacketAdapter inventoryProtector; public AuthMeInventoryPacketAdapter inventoryProtector;
public AuthMeTabCompletePacketAdapter tabComplete; public AuthMeTabCompletePacketAdapter tabComplete;
public AuthMeTablistPacketAdapter tablistHider;
/* /*
* Maps and stuff * Maps and stuff
@ -230,7 +232,7 @@ public class AuthMe extends JavaPlugin {
return; return;
} }
messages = new Messages(newSettings.getMessagesFile()); messages = new Messages(newSettings.getMessagesFile(), newSettings.getDefaultMessagesFile());
// Connect to the database and setup tables // Connect to the database and setup tables
try { try {
@ -665,10 +667,14 @@ public class AuthMe extends JavaPlugin {
inventoryProtector.unregister(); inventoryProtector.unregister();
inventoryProtector = null; inventoryProtector = null;
} }
if (tabComplete == null) { if (tabComplete == null && newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN)) {
tabComplete = new AuthMeTabCompletePacketAdapter(this); tabComplete = new AuthMeTabCompletePacketAdapter(this);
tabComplete.register(); tabComplete.register();
} }
if (tablistHider == null && newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) {
tablistHider = new AuthMeTablistPacketAdapter(this);
tablistHider.register();
}
} }
// Save Player Data // Save Player Data

View File

@ -36,6 +36,7 @@ public class PerformBackup {
* Constructor for PerformBackup. * Constructor for PerformBackup.
* *
* @param instance AuthMe * @param instance AuthMe
* @param settings The plugin settings
*/ */
public PerformBackup(AuthMe instance, NewSetting settings) { public PerformBackup(AuthMe instance, NewSetting settings) {
this.dataFolder = instance.getDataFolder(); this.dataFolder = instance.getDataFolder();

View File

@ -0,0 +1,90 @@
package fr.xephi.authme.events;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Common supertype for all AuthMe teleport events.
*/
public abstract class AbstractTeleportEvent extends CustomEvent implements Cancellable {
private final Player player;
private final Location from;
private Location to;
private boolean isCancelled;
/**
* Constructor.
*
* @param isAsync Whether to fire the event asynchronously or not
* @param player The player
* @param from The location the player is being teleported away from
* @param to The teleport destination
*/
public AbstractTeleportEvent(boolean isAsync, Player player, Location from, Location to) {
super(isAsync);
this.player = player;
this.from = from;
this.to = to;
}
/**
* Constructor, using the player's current location as "from" location.
*
* @param isAsync Whether to fire the event asynchronously or not
* @param player The player
* @param to The teleport destination
*/
public AbstractTeleportEvent(boolean isAsync, Player player, Location to) {
this(isAsync, player, player.getLocation(), to);
}
/**
* Return the player planned to be teleported.
*
* @return The player
*/
public Player getPlayer() {
return player;
}
/**
* Return the location the player is being teleported away from.
*
* @return The location prior to the teleport
*/
public Location getFrom() {
return from;
}
/**
* Set the destination of the teleport.
*
* @param to The location to teleport the player to
*/
public void setTo(Location to) {
this.to = to;
}
/**
* Return the destination the player is being teleported to.
*
* @return The teleport destination
*/
public Location getTo() {
return to;
}
@Override
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
}

View File

@ -5,21 +5,19 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* This event is call when a player try to /login * This event is called when a player uses the /login command with correct credentials.
* * {@link #setCanLogin(boolean) {@code event.setCanLogin(false)}} prevents the player from logging in.
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class AuthMeAsyncPreLoginEvent extends Event { public class AuthMeAsyncPreLoginEvent extends CustomEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final Player player; private final Player player;
private boolean canLogin = true; private boolean canLogin = true;
/** /**
* Constructor for AuthMeAsyncPreLoginEvent. * Constructor.
* *
* @param player Player * @param player The player
*/ */
public AuthMeAsyncPreLoginEvent(Player player) { public AuthMeAsyncPreLoginEvent(Player player) {
super(true); super(true);
@ -27,37 +25,41 @@ public class AuthMeAsyncPreLoginEvent extends Event {
} }
/** /**
* Method getPlayer. * Return the player concerned by this event.
* *
* @return Player * @return The player who executed a valid {@code /login} command
*/ */
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
/** /**
* Method canLogin. * Return whether the player is allowed to log in.
* *
* @return boolean * @return True if the player can log in, false otherwise
*/ */
public boolean canLogin() { public boolean canLogin() {
return canLogin; return canLogin;
} }
/** /**
* Method setCanLogin. * Define whether or not the player may log in.
* *
* @param canLogin boolean * @param canLogin True to allow the player to log in; false to prevent him
*/ */
public void setCanLogin(boolean canLogin) { public void setCanLogin(boolean canLogin) {
this.canLogin = canLogin; this.canLogin = canLogin;
} }
/** /**
* Method getHandlers. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @return HandlerList * @return The list of handlers
*/ */
public static HandlerList getHandlerList() {
return handlers;
}
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;

View File

@ -2,65 +2,38 @@ package fr.xephi.authme.events;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/** /**
* This event is call when AuthMe try to teleport a player * This event is fired before AuthMe teleports a player for general purposes.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class AuthMeTeleportEvent extends CustomEvent { public class AuthMeTeleportEvent extends AbstractTeleportEvent {
private final Player player; private static final HandlerList handlers = new HandlerList();
private Location to;
private final Location from;
/** /**
* Constructor for AuthMeTeleportEvent. * Constructor.
* *
* @param player Player * @param player The player
* @param to Location * @param to The teleport destination
*/ */
public AuthMeTeleportEvent(Player player, Location to) { public AuthMeTeleportEvent(Player player, Location to) {
this.player = player; super(false, player, to);
this.from = player.getLocation();
this.to = to;
} }
/** /**
* Method getPlayer. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @return Player * @return The list of handlers
*/ */
public Player getPlayer() { public static HandlerList getHandlerList() {
return player; return handlers;
} }
/** @Override
* Method getTo. public HandlerList getHandlers() {
* return handlers;
* @return Location
*/
public Location getTo() {
return to;
}
/**
* Method setTo.
*
* @param to Location
*/
public void setTo(Location to) {
this.to = to;
}
/**
* Method getFrom.
*
* @return Location
*/
public Location getFrom() {
return from;
} }
} }

View File

@ -1,67 +1,27 @@
package fr.xephi.authme.events; package fr.xephi.authme.events;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/** /**
* @author Xephi59 * The parent of all AuthMe events.
* @version $Revision: 1.0 $
*/ */
public class CustomEvent extends Event implements Cancellable { public abstract class CustomEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private boolean isCancelled;
/**
* Constructor.
*/
public CustomEvent() { public CustomEvent() {
super(false); super(false);
} }
/** /**
* Constructor for CustomEvent. * Constructor, specifying whether the event is asynchronous or not.
* *
* @param b boolean * @param isAsync {@code true} to fire the event asynchronously, false otherwise
* @see Event#Event(boolean)
*/ */
public CustomEvent(boolean b) { public CustomEvent(boolean isAsync) {
super(b); super(isAsync);
}
/**
* Method getHandlerList.
*
* @return HandlerList
*/
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Method getHandlers.
*
* @return HandlerList
*/
public HandlerList getHandlers() {
return handlers;
}
/**
* Method isCancelled.
*
* @return boolean * @see org.bukkit.event.Cancellable#isCancelled()
*/
public boolean isCancelled() {
return this.isCancelled;
}
/**
* Method setCancelled.
*
* @param cancelled boolean
*
* @see org.bukkit.event.Cancellable#setCancelled(boolean)
*/
public void setCancelled(boolean cancelled) {
this.isCancelled = cancelled;
} }
} }

View File

@ -2,67 +2,40 @@ package fr.xephi.authme.events;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/** /**
* Called if a player is teleported to the authme first spawn * Event that is called if a player is teleported to the AuthMe first spawn, i.e. to the
* * spawn location for players who have never played before.
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class FirstSpawnTeleportEvent extends CustomEvent { public class FirstSpawnTeleportEvent extends AbstractTeleportEvent {
private final Player player; private static final HandlerList handlers = new HandlerList();
private Location to;
private final Location from;
/** /**
* Constructor for FirstSpawnTeleportEvent. * Constructor.
* *
* @param player Player * @param player The player
* @param from Location * @param from The location the player is being teleported away from
* @param to Location * @param to The teleport destination
*/ */
public FirstSpawnTeleportEvent(Player player, Location from, Location to) { public FirstSpawnTeleportEvent(Player player, Location from, Location to) {
super(true); super(true, player, from, to);
this.player = player;
this.from = from;
this.to = to;
} }
/** /**
* Method getPlayer. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @return Player * @return The list of handlers
*/ */
public Player getPlayer() { public static HandlerList getHandlerList() {
return player; return handlers;
} }
/** @Override
* Method getTo. public HandlerList getHandlers() {
* return handlers;
* @return Location
*/
public Location getTo() {
return to;
}
/**
* Method setTo.
*
* @param to Location
*/
public void setTo(Location to) {
this.to = to;
}
/**
* Method getFrom.
*
* @return Location
*/
public Location getFrom() {
return from;
} }
} }

View File

@ -5,80 +5,40 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* This event is called when a player login or register through AuthMe. The * Event fired when a player has successfully logged in or registered.
* boolean 'isLogin' will be false if, and only if, login/register failed.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class LoginEvent extends Event { public class LoginEvent extends CustomEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Player player; private final Player player;
private boolean isLogin;
/** /**
* Constructor for LoginEvent. * Constructor.
* *
* @param player Player * @param player The player
* @param isLogin boolean
*/ */
public LoginEvent(Player player, boolean isLogin) { public LoginEvent(Player player) {
this.player = player; this.player = player;
this.isLogin = isLogin;
} }
/** /**
* Method getHandlerList. * Return the player that has successfully logged in or registered.
* *
* @return HandlerList * @return The player
*/
public Player getPlayer() {
return player;
}
/**
* Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
*
* @return The list of handlers
*/ */
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
/**
* Method getPlayer.
*
* @return Player
*/
public Player getPlayer() {
return this.player;
}
/**
* Method setPlayer.
*
* @param player Player
*/
public void setPlayer(Player player) {
this.player = player;
}
/**
* Method isLogin.
*
* @return boolean
*/
public boolean isLogin() {
return isLogin;
}
/**
* Method setLogin.
*
* @param isLogin boolean
*/
@Deprecated
public void setLogin(boolean isLogin) {
this.isLogin = isLogin;
}
/**
* Method getHandlers.
*
* @return HandlerList
*/
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;

View File

@ -5,57 +5,42 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* This event is called when a player logout through AuthMe. * This event is called when a player logs out through AuthMe, i.e. only when the player
* * has executed the {@code /logout} command. This event is not fired if a player simply
* @author Xephi59 * leaves the server.
* @version $Revision: 1.0 $
*/ */
public class LogoutEvent extends Event { public class LogoutEvent extends CustomEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private Player player; private final Player player;
/** /**
* Constructor for LogoutEvent. * Constructor.
* *
* @param player Player * @param player The player
*/ */
public LogoutEvent(Player player) { public LogoutEvent(Player player) {
this.player = player; this.player = player;
} }
/** /**
* Method getHandlerList. * Return the player who logged out.
* *
* @return HandlerList * @return The player
*/
public static HandlerList getHandlerList() {
return handlers;
}
/**
* Method getPlayer.
*
* @return Player
*/ */
public Player getPlayer() { public Player getPlayer() {
return this.player; return this.player;
} }
/** /**
* Method setPlayer. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @param player Player * @return The list of handlers
*/ */
public void setPlayer(Player player) { public static HandlerList getHandlerList() {
this.player = player; return handlers;
} }
/**
* Method getHandlers.
*
* @return HandlerList
*/
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;

View File

@ -5,24 +5,33 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* This event is called when we need to compare or hash password and allows * This event is called when we need to compare or hash a password for a player and allows
* third-party listeners to change the encryption method. This is typically * third-party listeners to change the encryption method. This is typically
* done with the {@link fr.xephi.authme.security.HashAlgorithm#CUSTOM} setting. * done with the {@link fr.xephi.authme.security.HashAlgorithm#CUSTOM} setting.
*
* @author Xephi59
*/ */
public class PasswordEncryptionEvent extends Event { public class PasswordEncryptionEvent extends CustomEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private EncryptionMethod method; private EncryptionMethod method;
private String playerName; private String playerName;
/**
* Constructor.
*
* @param method The method used to encrypt the password
* @param playerName The name of the player
*/
public PasswordEncryptionEvent(EncryptionMethod method, String playerName) { public PasswordEncryptionEvent(EncryptionMethod method, String playerName) {
super(false); super(false);
this.method = method; this.method = method;
this.playerName = playerName; this.playerName = playerName;
} }
/**
* Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
*
* @return The list of handlers
*/
public static HandlerList getHandlerList() { public static HandlerList getHandlerList() {
return handlers; return handlers;
} }
@ -32,14 +41,29 @@ public class PasswordEncryptionEvent extends Event {
return handlers; return handlers;
} }
/**
* Return the encryption method used to hash the password.
*
* @return The encryption method
*/
public EncryptionMethod getMethod() { public EncryptionMethod getMethod() {
return method; return method;
} }
/**
* Set the encryption method to hash the password with.
*
* @param method The encryption method to use
*/
public void setMethod(EncryptionMethod method) { public void setMethod(EncryptionMethod method) {
this.method = method; this.method = method;
} }
/**
* Return the name of the player the event has been fired for.
*
* @return The player name
*/
public String getPlayerName() { public String getPlayerName() {
return playerName; return playerName;
} }

View File

@ -1,98 +1,84 @@
package fr.xephi.authme.events; package fr.xephi.authme.events;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
/** /**
* This event is call just after store inventory into cache and will empty the * This event is called before the inventory data of a player is suppressed,
* player inventory. * i.e. the inventory of the player is not displayed until he has authenticated.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class ProtectInventoryEvent extends CustomEvent { public class ProtectInventoryEvent extends CustomEvent implements Cancellable {
private final ItemStack[] storedinventory; private static final HandlerList handlers = new HandlerList();
private final ItemStack[] storedarmor; private final ItemStack[] storedInventory;
private ItemStack[] emptyInventory = null; private final ItemStack[] storedArmor;
private ItemStack[] emptyArmor = null;
private final Player player; private final Player player;
private boolean isCancelled;
/** /**
* Constructor for ProtectInventoryEvent. * Constructor.
* *
* @param player Player * @param player The player
*/ */
public ProtectInventoryEvent(Player player) { public ProtectInventoryEvent(Player player) {
super(true); super(true);
this.player = player; this.player = player;
this.storedinventory = player.getInventory().getContents(); this.storedInventory = player.getInventory().getContents();
this.storedarmor = player.getInventory().getArmorContents(); this.storedArmor = player.getInventory().getArmorContents();
this.emptyInventory = new ItemStack[36];
this.emptyArmor = new ItemStack[4];
} }
/** /**
* Method getStoredInventory. * Return the inventory of the player.
* *
* @return ItemStack[] * @return The player's inventory
*/ */
public ItemStack[] getStoredInventory() { public ItemStack[] getStoredInventory() {
return this.storedinventory; return storedInventory;
} }
/** /**
* Method getStoredArmor. * Return the armor of the player.
* *
* @return ItemStack[] * @return The player's armor
*/ */
public ItemStack[] getStoredArmor() { public ItemStack[] getStoredArmor() {
return this.storedarmor; return storedArmor;
} }
/** /**
* Method getPlayer. * Return the player whose inventory will be hidden.
* *
* @return Player * @return The player associated with this event
*/ */
public Player getPlayer() { public Player getPlayer() {
return this.player; return player;
}
@Override
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
}
@Override
public boolean isCancelled() {
return isCancelled;
} }
/** /**
* Method setNewInventory. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @param emptyInventory ItemStack[] * @return The list of handlers
*/ */
public void setNewInventory(ItemStack[] emptyInventory) { public static HandlerList getHandlerList() {
this.emptyInventory = emptyInventory; return handlers;
} }
/** @Override
* Method getEmptyInventory. public HandlerList getHandlers() {
* return handlers;
* @return ItemStack[]
*/
public ItemStack[] getEmptyInventory() {
return this.emptyInventory;
}
/**
* Method setNewArmor.
*
* @param emptyArmor ItemStack[]
*/
public void setNewArmor(ItemStack[] emptyArmor) {
this.emptyArmor = emptyArmor;
}
/**
* Method getEmptyArmor.
*
* @return ItemStack[]
*/
public ItemStack[] getEmptyArmor() {
return this.emptyArmor;
} }
} }

View File

@ -1,67 +0,0 @@
package fr.xephi.authme.events;
import org.bukkit.Location;
import org.bukkit.entity.Player;
/**
* This event is call if, and only if, a player is teleported just after a
* register.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/
public class RegisterTeleportEvent extends CustomEvent {
private final Player player;
private Location to;
private final Location from;
/**
* Constructor for RegisterTeleportEvent.
*
* @param player Player
* @param to Location
*/
public RegisterTeleportEvent(Player player, Location to) {
this.player = player;
this.from = player.getLocation();
this.to = to;
}
/**
* Method getPlayer.
*
* @return Player
*/
public Player getPlayer() {
return player;
}
/**
* Method getTo.
*
* @return Location
*/
public Location getTo() {
return to;
}
/**
* Method setTo.
*
* @param to Location
*/
public void setTo(Location to) {
this.to = to;
}
/**
* Method getFrom.
*
* @return Location
*/
public Location getFrom() {
return from;
}
}

View File

@ -1,43 +0,0 @@
package fr.xephi.authme.events;
import org.bukkit.entity.Player;
/**
* This event is call when a creative inventory is reseted.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/
public class ResetInventoryEvent extends CustomEvent {
private Player player;
/**
* Constructor for ResetInventoryEvent.
*
* @param player Player
*/
public ResetInventoryEvent(Player player) {
super(true);
this.player = player;
}
/**
* Method getPlayer.
*
* @return Player
*/
public Player getPlayer() {
return this.player;
}
/**
* Method setPlayer.
*
* @param player Player
*/
public void setPlayer(Player player) {
this.player = player;
}
}

View File

@ -1,52 +1,60 @@
package fr.xephi.authme.events; package fr.xephi.authme.events;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/** /**
* This event restore the inventory. * This event is fired when the inventory of a player is restored
* * (the inventory data is no longer hidden from the user).
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class RestoreInventoryEvent extends CustomEvent { public class RestoreInventoryEvent extends CustomEvent implements Cancellable {
private Player player; private static final HandlerList handlers = new HandlerList();
private final Player player;
private boolean isCancelled;
/** /**
* Constructor for RestoreInventoryEvent. * Constructor.
* *
* @param player Player * @param player The player
*/ */
public RestoreInventoryEvent(Player player) { public RestoreInventoryEvent(Player player) {
this.player = player; this.player = player;
} }
/** /**
* Constructor for RestoreInventoryEvent. * Return the player whose inventory will be restored.
*
* @param player Player
* @param async boolean
*/
public RestoreInventoryEvent(Player player, boolean async) {
super(async);
this.player = player;
}
/**
* Method getPlayer.
* *
* @return Player * @return Player
*/ */
public Player getPlayer() { public Player getPlayer() {
return this.player; return player;
}
@Override
public boolean isCancelled() {
return isCancelled;
}
@Override
public void setCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
} }
/** /**
* Method setPlayer. * Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
* *
* @param player Player * @return The list of handlers
*/ */
public void setPlayer(Player player) { public static HandlerList getHandlerList() {
this.player = player; return handlers;
} }
@Override
public HandlerList getHandlers() {
return handlers;
}
} }

View File

@ -2,79 +2,51 @@ package fr.xephi.authme.events;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/** /**
* Called if a player is teleported to a specific spawn * Called if a player is teleported to a specific spawn upon joining or logging in.
*
* @author Xephi59
* @version $Revision: 1.0 $
*/ */
public class SpawnTeleportEvent extends CustomEvent { public class SpawnTeleportEvent extends AbstractTeleportEvent {
private final Player player; private static final HandlerList handlers = new HandlerList();
private Location to;
private final Location from;
private final boolean isAuthenticated; private final boolean isAuthenticated;
/** /**
* Constructor for SpawnTeleportEvent. * Constructor.
* *
* @param player Player * @param player The player
* @param from Location * @param from The location the player is being teleported away from
* @param to Location * @param to The teleport destination
* @param isAuthenticated boolean * @param isAuthenticated Whether or not the player is logged in
*/ */
public SpawnTeleportEvent(Player player, Location from, Location to, public SpawnTeleportEvent(Player player, Location from, Location to, boolean isAuthenticated) {
boolean isAuthenticated) { super(false, player, from, to);
this.player = player;
this.from = from;
this.to = to;
this.isAuthenticated = isAuthenticated; this.isAuthenticated = isAuthenticated;
} }
/** /**
* Method getPlayer. * Return whether or not the player is authenticated.
* *
* @return Player * @return true if the player is logged in, false otherwise
*/
public Player getPlayer() {
return player;
}
/**
* Method getTo.
*
* @return Location
*/
public Location getTo() {
return to;
}
/**
* Method setTo.
*
* @param to Location
*/
public void setTo(Location to) {
this.to = to;
}
/**
* Method getFrom.
*
* @return Location
*/
public Location getFrom() {
return from;
}
/**
* Method isAuthenticated.
*
* @return boolean
*/ */
public boolean isAuthenticated() { public boolean isAuthenticated() {
return isAuthenticated; return isAuthenticated;
} }
/**
* Return the list of handlers, equivalent to {@link #getHandlers()} and required by {@link Event}.
*
* @return The list of handlers
*/
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
} }

View File

@ -188,7 +188,33 @@ public class AuthMePlayerListener implements Listener {
} }
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onJoinMessage(PlayerJoinEvent event) {
final Player player = event.getPlayer();
if (player == null) {
return;
}
if (Settings.removeJoinMessage) {
event.setJoinMessage(null);
return;
}
if (!Settings.delayJoinMessage) {
return;
}
String name = player.getName().toLowerCase();
String joinMsg = event.getJoinMessage();
// Remove the join message while the player isn't logging in
if (joinMsg == null) {
return;
}
event.setJoinMessage(null);
joinMessage.put(name, joinMsg);
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (player == null) { if (player == null) {
@ -200,15 +226,6 @@ public class AuthMePlayerListener implements Listener {
player.setGameMode(GameMode.SURVIVAL); player.setGameMode(GameMode.SURVIVAL);
} }
String name = player.getName().toLowerCase();
String joinMsg = event.getJoinMessage();
// Remove the join message while the player isn't logging in
if (Settings.delayJoinLeaveMessages && joinMsg != null) {
event.setJoinMessage(null);
joinMessage.put(name, joinMsg);
}
// Shedule login task so works after the prelogin // Shedule login task so works after the prelogin
// (Fix found by Koolaid5000) // (Fix found by Koolaid5000)
Bukkit.getScheduler().runTask(plugin, new Runnable() { Bukkit.getScheduler().runTask(plugin, new Runnable() {
@ -348,7 +365,7 @@ public class AuthMePlayerListener implements Listener {
return; return;
} }
if (Settings.delayJoinLeaveMessages && !Utils.checkAuth(player)) { if (Settings.removeLeaveMessage) {
event.setQuitMessage(null); event.setQuitMessage(null);
} }
@ -374,11 +391,11 @@ public class AuthMePlayerListener implements Listener {
/* /*
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
* TODO #360: npc status can be used to bypass security!!! * Note #360: npc status can be used to bypass security!!!
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< * <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
*/ */
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerPickupItem(PlayerPickupItemEvent event) { public void onPlayerPickupItem(PlayerPickupItemEvent event) {
if (shouldCancelEvent(event)) { if (shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
@ -392,14 +409,14 @@ public class AuthMePlayerListener implements Listener {
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerConsumeItem(PlayerItemConsumeEvent event) { public void onPlayerConsumeItem(PlayerItemConsumeEvent event) {
if (shouldCancelEvent(event)) { if (shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInventoryOpen(InventoryOpenEvent event) { public void onPlayerInventoryOpen(InventoryOpenEvent event) {
final Player player = (Player) event.getPlayer(); final Player player = (Player) event.getPlayer();
@ -491,14 +508,14 @@ public class AuthMePlayerListener implements Listener {
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerShear(PlayerShearEntityEvent event) { public void onPlayerShear(PlayerShearEntityEvent event) {
if (shouldCancelEvent(event)) { if (shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);
} }
} }
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerFish(PlayerFishEvent event) { public void onPlayerFish(PlayerFishEvent event) {
if (shouldCancelEvent(event)) { if (shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);

View File

@ -10,7 +10,7 @@ import org.bukkit.event.player.PlayerEditBookEvent;
*/ */
public class AuthMePlayerListener16 implements Listener { public class AuthMePlayerListener16 implements Listener {
@EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerEditBook(PlayerEditBookEvent event) { public void onPlayerEditBook(PlayerEditBookEvent event) {
if (ListenerService.shouldCancelEvent(event)) { if (ListenerService.shouldCancelEvent(event)) {
event.setCancelled(true); event.setCancelled(true);

View File

@ -0,0 +1,44 @@
package fr.xephi.authme.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
public class AuthMeTablistPacketAdapter extends PacketAdapter {
public AuthMeTablistPacketAdapter(AuthMe plugin) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
}
@Override
public void onPacketSending(PacketEvent event)
{
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
try
{
if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
event.setCancelled(true);
}
}
catch (FieldAccessException e)
{
ConsoleLogger.showError("Couldn't access field.");
}
}
}
public void register() {
ProtocolLibrary.getProtocolManager().addPacketListener(this);
}
public void unregister() {
ProtocolLibrary.getProtocolManager().removePacketListener(this);
}
}

View File

@ -1,26 +1,33 @@
package fr.xephi.authme.output; package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File; import java.io.File;
/** /**
* Class for retrieving and sending translatable messages to players. * Class for retrieving and sending translatable messages to players.
* This class detects when the language settings have changed and will
* automatically update to use a new language file.
*/ */
public class Messages { public class Messages {
private MessagesManager manager; private FileConfiguration configuration;
private String fileName;
private final File defaultFile;
private FileConfiguration defaultConfiguration;
/** /**
* Constructor. * Constructor.
* *
* @param messageFile The messages file to use * @param messageFile The messages file to use
* @param defaultFile The file with messages to use as default if missing
*/ */
public Messages(File messageFile) { public Messages(File messageFile, File defaultFile) {
manager = new MessagesManager(messageFile); initializeFile(messageFile);
this.defaultFile = defaultFile;
} }
/** /**
@ -30,7 +37,7 @@ public class Messages {
* @param key The key of the message to send * @param key The key of the message to send
*/ */
public void send(CommandSender sender, MessageKey key) { public void send(CommandSender sender, MessageKey key) {
String[] lines = manager.retrieve(key.getKey()); String[] lines = retrieve(key);
for (String line : lines) { for (String line : lines) {
sender.sendMessage(line); sender.sendMessage(line);
} }
@ -38,7 +45,7 @@ public class Messages {
/** /**
* Send the given message code to the player with the given tag replacements. Note that this method * Send the given message code to the player with the given tag replacements. Note that this method
* issues an exception if the number of supplied replacements doesn't correspond to the number of tags * logs an error if the number of supplied replacements doesn't correspond to the number of tags
* the message key contains. * the message key contains.
* *
* @param sender The entity to send the message to * @param sender The entity to send the message to
@ -48,13 +55,13 @@ public class Messages {
public void send(CommandSender sender, MessageKey key, String... replacements) { public void send(CommandSender sender, MessageKey key, String... replacements) {
String message = retrieveSingle(key); String message = retrieveSingle(key);
String[] tags = key.getTags(); String[] tags = key.getTags();
if (replacements.length != tags.length) { if (replacements.length == tags.length) {
throw new IllegalStateException( for (int i = 0; i < tags.length; ++i) {
"Given replacement size does not match the tags in message key '" + key + "'"); message = message.replace(tags[i], replacements[i]);
} }
} else {
for (int i = 0; i < tags.length; ++i) { ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
message = message.replace(tags[i], replacements[i]); send(sender, key);
} }
for (String line : message.split("\n")) { for (String line : message.split("\n")) {
@ -66,18 +73,24 @@ public class Messages {
* Retrieve the message from the text file and return it split by new line as an array. * Retrieve the message from the text file and return it split by new line as an array.
* *
* @param key The message key to retrieve * @param key The message key to retrieve
*
* @return The message split by new lines * @return The message split by new lines
*/ */
public String[] retrieve(MessageKey key) { public String[] retrieve(MessageKey key) {
return manager.retrieve(key.getKey()); final String code = key.getKey();
String message = configuration.getString(code);
if (message == null) {
ConsoleLogger.showError("Error getting message with key '" + code + "'. "
+ "Please verify your config file at '" + fileName + "'");
return formatMessage(getDefault(code));
}
return formatMessage(message);
} }
/** /**
* Retrieve the message from the text file. * Retrieve the message from the text file.
* *
* @param key The message key to retrieve * @param key The message key to retrieve
*
* @return The message from the file * @return The message from the file
*/ */
public String retrieveSingle(MessageKey key) { public String retrieveSingle(MessageKey key) {
@ -86,9 +99,40 @@ public class Messages {
/** /**
* Reload the messages manager. * Reload the messages manager.
*
* @param messagesFile The new file to load messages from
*/ */
public void reload(File messagesFile) { public void reload(File messagesFile) {
manager = new MessagesManager(messagesFile); initializeFile(messagesFile);
}
private void initializeFile(File messageFile) {
this.configuration = YamlConfiguration.loadConfiguration(messageFile);
this.fileName = messageFile.getName();
}
private String getDefault(String code) {
if (defaultFile == null) {
return getDefaultErrorMessage(code);
}
if (defaultConfiguration == null) {
defaultConfiguration = YamlConfiguration.loadConfiguration(defaultFile);
}
String message = defaultConfiguration.getString(code);
return message == null ? getDefaultErrorMessage(code) : message;
}
private static String getDefaultErrorMessage(String code) {
return "Error retrieving message '" + code + "'";
}
private static String[] formatMessage(String message) {
String[] lines = message.split("&n");
for (int i = 0; i < lines.length; ++i) {
lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
}
return lines;
} }
} }

View File

@ -1,58 +0,0 @@
package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
/**
* Class responsible for reading messages from a file and formatting them for Minecraft.
* <p>
* This class is used within {@link Messages}, which offers a high-level interface for accessing
* or sending messages from a properties file.
*/
class MessagesManager {
private final YamlConfiguration configuration;
private final String fileName;
/**
* Constructor for Messages.
*
* @param file the configuration file
*/
MessagesManager(File file) {
this.fileName = file.getName();
this.configuration = YamlConfiguration.loadConfiguration(file);
}
/**
* Retrieve the message from the configuration file.
*
* @param key The key to retrieve
*
* @return The message
*/
public String[] retrieve(String key) {
String message = configuration.getString(key);
if (message != null) {
return formatMessage(message);
}
// Message is null: log key not being found and send error back as message
String retrievalError = "Error getting message with key '" + key + "'. ";
ConsoleLogger.showError(retrievalError + "Please verify your config file at '" + fileName + "'");
return new String[]{
retrievalError + "Please contact the admin to verify or update the AuthMe messages file."};
}
private static String[] formatMessage(String message) {
String[] lines = message.split("&n");
for (int i = 0; i < lines.length; ++i) {
lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
}
return lines;
}
}

View File

@ -26,6 +26,7 @@ public class Management {
* Constructor for Management. * Constructor for Management.
* *
* @param plugin AuthMe * @param plugin AuthMe
* @param settings The plugin settings
*/ */
public Management(AuthMe plugin, NewSetting settings) { public Management(AuthMe plugin, NewSetting settings) {
this.plugin = plugin; this.plugin = plugin;

View File

@ -80,18 +80,17 @@ public class AsynchronousJoin {
if (Settings.getMaxJoinPerIp > 0 if (Settings.getMaxJoinPerIp > 0
&& !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS)
&& !ip.equalsIgnoreCase("127.0.0.1") && !ip.equalsIgnoreCase("127.0.0.1")
&& !ip.equalsIgnoreCase("localhost")) { && !ip.equalsIgnoreCase("localhost")
if (plugin.hasJoinedIp(player.getName(), ip)) { && plugin.hasJoinedIp(player.getName(), ip)) {
sched.scheduleSyncDelayedTask(plugin, new Runnable() { sched.scheduleSyncDelayedTask(plugin, new Runnable() {
@Override @Override
public void run() { public void run() {
player.kickPlayer("A player with the same IP is already in game!"); player.kickPlayer("A player with the same IP is already in game!");
} }
}); });
return; return;
}
} }
final Location spawnLoc = plugin.getSpawnLocation(player); final Location spawnLoc = plugin.getSpawnLocation(player);
final boolean isAuthAvailable = database.isAuthAvailable(name); final boolean isAuthAvailable = database.isAuthAvailable(name);
@ -104,12 +103,9 @@ public class AsynchronousJoin {
public void run() { public void run() {
SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnLoc, PlayerCache.getInstance().isAuthenticated(name)); SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnLoc, PlayerCache.getInstance().isAuthenticated(name));
plugin.getServer().getPluginManager().callEvent(tpEvent); plugin.getServer().getPluginManager().callEvent(tpEvent);
if (!tpEvent.isCancelled()) { if (!tpEvent.isCancelled() && player.isOnline() && tpEvent.getTo() != null
if (player.isOnline() && tpEvent.getTo() != null) { && tpEvent.getTo().getWorld() != null) {
if (tpEvent.getTo().getWorld() != null) { player.teleport(tpEvent.getTo());
player.teleport(tpEvent.getTo());
}
}
} }
} }
@ -155,25 +151,21 @@ public class AsynchronousJoin {
return; return;
} }
if (!Settings.noTeleport) { if (!Settings.noTeleport && !needFirstSpawn() && Settings.isTeleportToSpawnEnabled
if (!needFirstSpawn() && Settings.isTeleportToSpawnEnabled || (Settings.isForceSpawnLocOnJoinEnabled && Settings.getForcedWorlds.contains(player.getWorld().getName()))) { || (Settings.isForceSpawnLocOnJoinEnabled && Settings.getForcedWorlds.contains(player.getWorld().getName()))) {
sched.scheduleSyncDelayedTask(plugin, new Runnable() { sched.scheduleSyncDelayedTask(plugin, new Runnable() {
@Override @Override
public void run() { public void run() {
SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnLoc, PlayerCache.getInstance().isAuthenticated(name)); SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnLoc, PlayerCache.getInstance().isAuthenticated(name));
plugin.getServer().getPluginManager().callEvent(tpEvent); plugin.getServer().getPluginManager().callEvent(tpEvent);
if (!tpEvent.isCancelled()) { if (!tpEvent.isCancelled() && player.isOnline() && tpEvent.getTo() != null
if (player.isOnline() && tpEvent.getTo() != null) { && tpEvent.getTo().getWorld() != null) {
if (tpEvent.getTo().getWorld() != null) { player.teleport(tpEvent.getTo());
player.teleport(tpEvent.getTo()); }
} }
}
}
}
}); });
}
} }
} }

View File

@ -28,8 +28,7 @@ import fr.xephi.authme.util.Utils.GroupType;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
/**
*/
public class ProcessSyncPlayerLogin implements Runnable { public class ProcessSyncPlayerLogin implements Runnable {
private final LimboPlayer limbo; private final LimboPlayer limbo;
@ -47,7 +46,8 @@ public class ProcessSyncPlayerLogin implements Runnable {
* *
* @param player Player * @param player Player
* @param plugin AuthMe * @param plugin AuthMe
* @param database DataSource * @param database DataSource
* @param settings The plugin settings
*/ */
public ProcessSyncPlayerLogin(Player player, AuthMe plugin, public ProcessSyncPlayerLogin(Player player, AuthMe plugin,
DataSource database, NewSetting settings) { DataSource database, NewSetting settings) {
@ -62,24 +62,19 @@ public class ProcessSyncPlayerLogin implements Runnable {
this.settings = settings; this.settings = settings;
} }
/**
* Method getLimbo.
*
* @return LimboPlayer
*/
public LimboPlayer getLimbo() { public LimboPlayer getLimbo() {
return limbo; return limbo;
} }
protected void restoreOpState() { private void restoreOpState() {
player.setOp(limbo.getOperator()); player.setOp(limbo.getOperator());
} }
protected void packQuitLocation() { private void packQuitLocation() {
Utils.packCoords(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld(), player); Utils.packCoords(auth.getQuitLocX(), auth.getQuitLocY(), auth.getQuitLocZ(), auth.getWorld(), player);
} }
protected void teleportBackFromSpawn() { private void teleportBackFromSpawn() {
AuthMeTeleportEvent tpEvent = new AuthMeTeleportEvent(player, limbo.getLoc()); AuthMeTeleportEvent tpEvent = new AuthMeTeleportEvent(player, limbo.getLoc());
pm.callEvent(tpEvent); pm.callEvent(tpEvent);
if (!tpEvent.isCancelled() && tpEvent.getTo() != null) { if (!tpEvent.isCancelled() && tpEvent.getTo() != null) {
@ -87,7 +82,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
} }
} }
protected void teleportToSpawn() { private void teleportToSpawn() {
Location spawnL = plugin.getSpawnLocation(player); Location spawnL = plugin.getSpawnLocation(player);
SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnL, true); SpawnTeleportEvent tpEvent = new SpawnTeleportEvent(player, player.getLocation(), spawnL, true);
pm.callEvent(tpEvent); pm.callEvent(tpEvent);
@ -96,14 +91,14 @@ public class ProcessSyncPlayerLogin implements Runnable {
} }
} }
protected void restoreSpeedEffects() { private void restoreSpeedEffects() {
if (Settings.isRemoveSpeedEnabled) { if (Settings.isRemoveSpeedEnabled) {
player.setWalkSpeed(0.2F); player.setWalkSpeed(0.2F);
player.setFlySpeed(0.1F); player.setFlySpeed(0.1F);
} }
} }
protected void restoreInventory() { private void restoreInventory() {
RestoreInventoryEvent event = new RestoreInventoryEvent(player); RestoreInventoryEvent event = new RestoreInventoryEvent(player);
pm.callEvent(event); pm.callEvent(event);
if (!event.isCancelled() && plugin.inventoryProtector != null) { if (!event.isCancelled() && plugin.inventoryProtector != null) {
@ -111,7 +106,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
} }
} }
protected void forceCommands() { private void forceCommands() {
for (String command : Settings.forceCommands) { for (String command : Settings.forceCommands) {
player.performCommand(command.replace("%p", player.getName())); player.performCommand(command.replace("%p", player.getName()));
} }
@ -120,7 +115,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
} }
} }
protected void sendBungeeMessage() { private void sendBungeeMessage() {
ByteArrayDataOutput out = ByteStreams.newDataOutput(); ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Forward"); out.writeUTF("Forward");
out.writeUTF("ALL"); out.writeUTF("ALL");
@ -129,11 +124,6 @@ public class ProcessSyncPlayerLogin implements Runnable {
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
} }
/**
* Method run.
*
* @see java.lang.Runnable#run()
*/
@Override @Override
public void run() { public void run() {
// Limbo contains the State of the Player before /login // Limbo contains the State of the Player before /login
@ -174,8 +164,9 @@ public class ProcessSyncPlayerLogin implements Runnable {
if (jm != null) { if (jm != null) {
if (!jm.isEmpty()) { if (!jm.isEmpty()) {
for (Player p : Utils.getOnlinePlayers()) { for (Player p : Utils.getOnlinePlayers()) {
if (p.isOnline()) if (p.isOnline()) {
p.sendMessage(jm); p.sendMessage(jm);
}
} }
} }
AuthMePlayerListener.joinMessage.remove(name); AuthMePlayerListener.joinMessage.remove(name);
@ -187,12 +178,13 @@ public class ProcessSyncPlayerLogin implements Runnable {
} }
// The Login event now fires (as intended) after everything is processed // The Login event now fires (as intended) after everything is processed
Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player));
player.saveData(); player.saveData();
if (Settings.bungee) if (Settings.bungee) {
sendBungeeMessage(); sendBungeeMessage();
}
// Login is finish, display welcome message if we use email registration // Login is finish, display welcome message if we use email registration
if (Settings.useWelcomeMessage && Settings.emailRegistration) if (Settings.useWelcomeMessage && Settings.emailRegistration) {
if (Settings.broadcastWelcomeMessage) { if (Settings.broadcastWelcomeMessage) {
for (String s : settings.getWelcomeMessage()) { for (String s : settings.getWelcomeMessage()) {
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
@ -202,6 +194,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
player.sendMessage(plugin.replaceAllInfo(s, player)); player.sendMessage(plugin.replaceAllInfo(s, player));
} }
} }
}
// Login is now finished; we can force all commands // Login is now finished; we can force all commands
forceCommands(); forceCommands();

View File

@ -39,6 +39,7 @@ public class ProcessSyncPasswordRegister implements Runnable {
* *
* @param player Player * @param player Player
* @param plugin AuthMe * @param plugin AuthMe
* @param settings The plugin settings
*/ */
public ProcessSyncPasswordRegister(Player player, AuthMe plugin, NewSetting settings) { public ProcessSyncPasswordRegister(Player player, AuthMe plugin, NewSetting settings) {
this.m = plugin.getMessages(); this.m = plugin.getMessages();
@ -119,7 +120,7 @@ public class ProcessSyncPasswordRegister implements Runnable {
} }
// The LoginEvent now fires (as intended) after everything is processed // The LoginEvent now fires (as intended) after everything is processed
plugin.getServer().getPluginManager().callEvent(new LoginEvent(player, true)); plugin.getServer().getPluginManager().callEvent(new LoginEvent(player));
player.saveData(); player.saveData();
if (!Settings.noConsoleSpam) { if (!Settings.noConsoleSpam) {

View File

@ -13,6 +13,7 @@ public enum HashAlgorithm {
CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class), CRAZYCRYPT1(fr.xephi.authme.security.crypts.CRAZYCRYPT1.class),
DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class), DOUBLEMD5(fr.xephi.authme.security.crypts.DOUBLEMD5.class),
IPB3(fr.xephi.authme.security.crypts.IPB3.class), IPB3(fr.xephi.authme.security.crypts.IPB3.class),
IPB4(fr.xephi.authme.security.crypts.IPB4.class),
JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class), JOOMLA(fr.xephi.authme.security.crypts.JOOMLA.class),
MD5(fr.xephi.authme.security.crypts.MD5.class), MD5(fr.xephi.authme.security.crypts.MD5.class),
MD5VB(fr.xephi.authme.security.crypts.MD5VB.class), MD5VB(fr.xephi.authme.security.crypts.MD5VB.class),
@ -29,8 +30,8 @@ public enum HashAlgorithm {
SHA1(fr.xephi.authme.security.crypts.SHA1.class), SHA1(fr.xephi.authme.security.crypts.SHA1.class),
SHA256(fr.xephi.authme.security.crypts.SHA256.class), SHA256(fr.xephi.authme.security.crypts.SHA256.class),
SHA512(fr.xephi.authme.security.crypts.SHA512.class), SHA512(fr.xephi.authme.security.crypts.SHA512.class),
TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class),
SMF(fr.xephi.authme.security.crypts.SMF.class), SMF(fr.xephi.authme.security.crypts.SMF.class),
TWO_FACTOR(fr.xephi.authme.security.crypts.TwoFactor.class),
WBB3(fr.xephi.authme.security.crypts.WBB3.class), WBB3(fr.xephi.authme.security.crypts.WBB3.class),
WBB4(fr.xephi.authme.security.crypts.WBB4.class), WBB4(fr.xephi.authme.security.crypts.WBB4.class),
WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class), WHIRLPOOL(fr.xephi.authme.security.crypts.WHIRLPOOL.class),

View File

@ -8,18 +8,10 @@ import java.util.Random;
*/ */
public final class RandomString { public final class RandomString {
private static final char[] chars = new char[36]; private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom(); private static final Random RANDOM = new SecureRandom();
private static final int HEX_MAX_INDEX = 16; private static final int HEX_MAX_INDEX = 16;
private static final int LOWER_ALPHANUMERIC_INDEX = 36;
static {
for (int idx = 0; idx < 10; ++idx) {
chars[idx] = (char) ('0' + idx);
}
for (int idx = 10; idx < 36; ++idx) {
chars[idx] = (char) ('a' + idx - 10);
}
}
private RandomString() { private RandomString() {
} }
@ -31,7 +23,7 @@ public final class RandomString {
* @return The random string * @return The random string
*/ */
public static String generate(int length) { public static String generate(int length) {
return generate(length, chars.length); return generate(length, LOWER_ALPHANUMERIC_INDEX);
} }
/** /**
@ -45,13 +37,24 @@ public final class RandomString {
return generate(length, HEX_MAX_INDEX); return generate(length, HEX_MAX_INDEX);
} }
/**
* Generate a random string with digits and lowercase and uppercase letters. The result of this
* method matches the pattern [0-9a-zA-Z].
*
* @param length The length of the random string to generate
* @return The random string
*/
public static String generateLowerUpper(int length) {
return generate(length, CHARS.length());
}
private static String generate(int length, int maxIndex) { private static String generate(int length, int maxIndex) {
if (length < 0) { if (length < 0) {
throw new IllegalArgumentException("Length must be positive but was " + length); throw new IllegalArgumentException("Length must be positive but was " + length);
} }
StringBuilder sb = new StringBuilder(length); StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
sb.append(chars[RANDOM.nextInt(maxIndex)]); sb.append(CHARS.charAt(RANDOM.nextInt(maxIndex)));
} }
return sb.toString(); return sb.toString();
} }

View File

@ -388,7 +388,7 @@ public class BCryptService {
private static String encode_base64(byte d[], int len) private static String encode_base64(byte d[], int len)
throws IllegalArgumentException { throws IllegalArgumentException {
int off = 0; int off = 0;
StringBuffer rs = new StringBuffer(); StringBuilder rs = new StringBuilder();
int c1, c2; int c1, c2;
if (len <= 0 || len > d.length) if (len <= 0 || len > d.length)
@ -441,7 +441,7 @@ public class BCryptService {
*/ */
private static byte[] decode_base64(String s, int maxolen) private static byte[] decode_base64(String s, int maxolen)
throws IllegalArgumentException { throws IllegalArgumentException {
StringBuffer rs = new StringBuffer(); StringBuilder rs = new StringBuilder();
int off = 0, slen = s.length(), olen = 0; int off = 0, slen = s.length(), olen = 0;
byte ret[]; byte ret[];
byte c1, c2, c3, c4, o; byte c1, c2, c3, c4, o;
@ -486,7 +486,7 @@ public class BCryptService {
* @param lr an array containing the two 32-bit half blocks * @param lr an array containing the two 32-bit half blocks
* @param off the position in the array of the blocks * @param off the position in the array of the blocks
*/ */
private final void encipher(int lr[], int off) { private void encipher(int lr[], int off) {
int i, n, l = lr[off], r = lr[off + 1]; int i, n, l = lr[off], r = lr[off + 1];
l ^= P[0]; l ^= P[0];
@ -534,8 +534,8 @@ public class BCryptService {
* Initialise the Blowfish key schedule * Initialise the Blowfish key schedule
*/ */
private void init_key() { private void init_key() {
P = (int[])P_orig.clone(); P = P_orig.clone();
S = (int[])S_orig.clone(); S = S_orig.clone();
} }
/** /**
@ -653,8 +653,8 @@ public class BCryptService {
String real_salt; String real_salt;
byte passwordb[], saltb[], hashed[]; byte passwordb[], saltb[], hashed[];
char minor = (char)0; char minor = (char)0;
int rounds, off = 0; int rounds, off;
StringBuffer rs = new StringBuffer(); StringBuilder rs = new StringBuilder();
if (salt.charAt(0) != '$' || salt.charAt(1) != '2') if (salt.charAt(0) != '$' || salt.charAt(1) != '2')
throw new IllegalArgumentException ("Invalid salt version"); throw new IllegalArgumentException ("Invalid salt version");
@ -684,8 +684,7 @@ public class BCryptService {
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
B = new BCryptService(); B = new BCryptService();
hashed = B.crypt_raw(passwordb, saltb, rounds, hashed = B.crypt_raw(passwordb, saltb, rounds, bf_crypt_ciphertext.clone());
(int[])bf_crypt_ciphertext.clone());
rs.append("$2"); rs.append("$2");
if (minor >= 'a') if (minor >= 'a')
@ -714,7 +713,7 @@ public class BCryptService {
* @return an encoded salt value * @return an encoded salt value
*/ */
public static String gensalt(int log_rounds, SecureRandom random) { public static String gensalt(int log_rounds, SecureRandom random) {
StringBuffer rs = new StringBuffer(); StringBuilder rs = new StringBuilder();
byte rnd[] = new byte[BCRYPT_SALT_LEN]; byte rnd[] = new byte[BCRYPT_SALT_LEN];
random.nextBytes(rnd); random.nextBytes(rnd);

View File

@ -0,0 +1,53 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.security.crypts.description.HasSalt;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.Usage;
import fr.xephi.authme.util.StringUtils;
/**
* Implementation for IPB4 (Invision Power Board 4).
* <p>
* The hash uses standard BCrypt with 13 as log<sub>2</sub> number of rounds. Additionally,
* IPB4 requires that the salt be stored additionally in the column "members_pass_hash"
* (even though BCrypt hashes already have the salt in the result).
*/
@Recommendation(Usage.DOES_NOT_WORK)
@HasSalt(value = SaltType.TEXT, length = 22)
public class IPB4 implements EncryptionMethod {
@Override
public String computeHash(String password, String salt, String name) {
return BCryptService.hashpw(password, "$2a$13$" + salt);
}
@Override
public HashedPassword computeHash(String password, String name) {
String salt = generateSalt();
return new HashedPassword(computeHash(password, salt, name), salt);
}
@Override
public boolean comparePassword(String password, HashedPassword hash, String name) {
try {
return hash.getHash().length() > 3 && BCryptService.checkpw(password, hash.getHash());
} catch (IllegalArgumentException e) {
ConsoleLogger.showError("Bcrypt checkpw() returned " + StringUtils.formatException(e));
}
return false;
}
@Override
public String generateSalt() {
return RandomString.generateLowerUpper(22);
}
@Override
public boolean hasSeparateSalt() {
return true;
}
}

View File

@ -18,6 +18,7 @@ import org.yaml.snakeyaml.Yaml;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -108,6 +109,21 @@ public class NewSetting {
return messagesFile; return messagesFile;
} }
/**
* Return the default messages file within the JAR that should contain all messages.
*
* @return The default messages file, or {@code null} if it could not be retrieved
*/
public File getDefaultMessagesFile() {
String defaultFilePath = "/messages/messages_en.yml";
URL url = NewSetting.class.getResource(defaultFilePath);
if (url == null) {
return null;
}
File file = new File(url.getFile());
return file.exists() ? file : null;
}
public String getEmailMessage() { public String getEmailMessage() {
return emailMessage; return emailMessage;
} }

View File

@ -1,14 +1,18 @@
package fr.xephi.authme.settings; package fr.xephi.authme.settings;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.datasource.DataSourceType; import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.Wrapper; import fr.xephi.authme.util.Wrapper;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -22,8 +26,6 @@ public final class Settings {
public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder();
public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules");
public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache");
private static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml");
public static final File LOG_FILE = new File(PLUGIN_FOLDER, "authme.log");
// This is not an option! // This is not an option!
public static boolean antiBotInAction = false; public static boolean antiBotInAction = false;
public static List<String> allowCommands; public static List<String> allowCommands;
@ -63,7 +65,8 @@ public final class Settings {
purgeLimitedCreative, purgeAntiXray, purgePermissions, purgeLimitedCreative, purgeAntiXray, purgePermissions,
enableProtection, enableAntiBot, recallEmail, useWelcomeMessage, enableProtection, enableAntiBot, recallEmail, useWelcomeMessage,
broadcastWelcomeMessage, forceRegKick, forceRegLogin, broadcastWelcomeMessage, forceRegKick, forceRegLogin,
checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect, checkVeryGames, removeJoinMessage, removeLeaveMessage, delayJoinMessage,
noTeleport, applyBlindEffect, hideTablistBeforeLogin, denyTabcompleteBeforeLogin,
kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional, kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional,
customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase; customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase;
public static String getNickRegex, getUnloggedinGroup, getMySQLHost, public static String getNickRegex, getUnloggedinGroup, getMySQLHost,
@ -103,7 +106,7 @@ public final class Settings {
} }
public static void loadVariables() { public static void loadVariables() {
isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false); isPermissionCheckEnabled = load(PluginSettings.ENABLE_PERMISSION_CHECK);
isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true); isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true);
isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true); isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true);
isTeleportToSpawnEnabled = configFile.getBoolean("settings.restrictions.teleportUnAuthedToSpawn", false); isTeleportToSpawnEnabled = configFile.getBoolean("settings.restrictions.teleportUnAuthedToSpawn", false);
@ -130,16 +133,16 @@ public final class Settings {
isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false); isSaveQuitLocationEnabled = configFile.getBoolean("settings.restrictions.SaveQuitLocation", false);
isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false); isForceSurvivalModeEnabled = configFile.getBoolean("settings.GameMode.ForceSurvivalMode", false);
getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp", 1); getmaxRegPerIp = configFile.getInt("settings.restrictions.maxRegPerIp", 1);
getPasswordHash = getPasswordHash(); getPasswordHash = load(SecuritySettings.PASSWORD_HASH);
getUnloggedinGroup = configFile.getString("settings.security.unLoggedinGroup", "unLoggedInGroup"); getUnloggedinGroup = load(SecuritySettings.UNLOGGEDIN_GROUP);
getDataSource = getDataSource(); getDataSource = load(DatabaseSettings.BACKEND);
isCachingEnabled = configFile.getBoolean("DataSource.caching", true); isCachingEnabled = load(DatabaseSettings.USE_CACHING);
getMySQLHost = configFile.getString("DataSource.mySQLHost", "127.0.0.1"); getMySQLHost = load(DatabaseSettings.MYSQL_HOST);
getMySQLPort = configFile.getString("DataSource.mySQLPort", "3306"); getMySQLPort = load(DatabaseSettings.MYSQL_PORT);
getMySQLUsername = configFile.getString("DataSource.mySQLUsername", "authme"); getMySQLUsername = load(DatabaseSettings.MYSQL_USERNAME);
getMySQLPassword = configFile.getString("DataSource.mySQLPassword", "12345"); getMySQLPassword = load(DatabaseSettings.MYSQL_PASSWORD);
getMySQLDatabase = configFile.getString("DataSource.mySQLDatabase", "authme"); getMySQLDatabase = load(DatabaseSettings.MYSQL_DATABASE);
getMySQLTablename = configFile.getString("DataSource.mySQLTablename", "authme"); getMySQLTablename = load(DatabaseSettings.MYSQL_TABLE);
getMySQLColumnEmail = configFile.getString("DataSource.mySQLColumnEmail", "email"); getMySQLColumnEmail = configFile.getString("DataSource.mySQLColumnEmail", "email");
getMySQLColumnName = configFile.getString("DataSource.mySQLColumnName", "username"); getMySQLColumnName = configFile.getString("DataSource.mySQLColumnName", "username");
getMySQLColumnPassword = configFile.getString("DataSource.mySQLColumnPassword", "password"); getMySQLColumnPassword = configFile.getString("DataSource.mySQLColumnPassword", "password");
@ -161,12 +164,15 @@ public final class Settings {
} }
getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup", ""); getRegisteredGroup = configFile.getString("GroupOptions.RegisteredPlayerGroup", "");
enablePasswordConfirmation = configFile.getBoolean("settings.restrictions.enablePasswordConfirmation", true); enablePasswordConfirmation = load(RestrictionSettings.ENABLE_PASSWORD_CONFIRMATION);
protectInventoryBeforeLogInEnabled = load(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN);
denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN);
protectInventoryBeforeLogInEnabled = configFile.getBoolean("settings.restrictions.ProtectInventoryBeforeLogIn", true);
plugin.checkProtocolLib(); plugin.checkProtocolLib();
passwordMaxLength = configFile.getInt("settings.security.passwordMaxLength", 20); passwordMaxLength = load(SecuritySettings.MAX_PASSWORD_LENGTH);
backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true);
@ -240,7 +246,9 @@ public final class Settings {
getMaxLoginPerIp = configFile.getInt("settings.restrictions.maxLoginPerIp", 0); getMaxLoginPerIp = configFile.getInt("settings.restrictions.maxLoginPerIp", 0);
getMaxJoinPerIp = configFile.getInt("settings.restrictions.maxJoinPerIp", 0); getMaxJoinPerIp = configFile.getInt("settings.restrictions.maxJoinPerIp", 0);
checkVeryGames = configFile.getBoolean("VeryGames.enableIpCheck", false); checkVeryGames = configFile.getBoolean("VeryGames.enableIpCheck", false);
delayJoinLeaveMessages = configFile.getBoolean("settings.delayJoinLeaveMessages", false); removeJoinMessage = load(RegistrationSettings.REMOVE_JOIN_MESSAGE);
removeLeaveMessage = load(RegistrationSettings.REMOVE_LEAVE_MESSAGE);
delayJoinMessage = load(RegistrationSettings.DELAY_JOIN_MESSAGE);
noTeleport = configFile.getBoolean("settings.restrictions.noTeleport", false); noTeleport = configFile.getBoolean("settings.restrictions.noTeleport", false);
crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db"); crazyloginFileName = configFile.getString("Converter.CrazyLogin.fileName", "accounts.db");
getPassRegex = configFile.getString("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*"); getPassRegex = configFile.getString("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*");
@ -257,70 +265,6 @@ public final class Settings {
} }
/**
* Method getPasswordHash.
*
* @return HashAlgorithm
*/
private static HashAlgorithm getPasswordHash() {
String key = "settings.security.passwordHash";
try {
return HashAlgorithm.valueOf(configFile.getString(key, "SHA256").toUpperCase());
} catch (IllegalArgumentException ex) {
ConsoleLogger.showError("Unknown Hash Algorithm; defaulting to SHA256");
return HashAlgorithm.SHA256;
}
}
/**
* Method getDataSource.
*
* @return DataSourceType
*/
private static DataSourceType getDataSource() {
String key = "DataSource.backend";
try {
return DataSourceType.valueOf(configFile.getString(key, "sqlite").toUpperCase());
} catch (IllegalArgumentException ex) {
ConsoleLogger.showError("Unknown database backend; defaulting to SQLite database");
return DataSourceType.SQLITE;
}
}
/**
* Saves the configuration to disk
*
* @return True if saved successfully
*/
private static boolean save() {
try {
configFile.save(SETTINGS_FILE);
return true;
} catch (IOException ex) {
return false;
}
}
/**
* Method checkLang.
*
* @param lang String
*
* @return String
*/
private static String checkLang(String lang) {
if (new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + lang + ".yml").exists()) {
ConsoleLogger.info("Set Language to: " + lang);
return lang;
}
if (AuthMe.class.getResourceAsStream("/messages/messages_" + lang + ".yml") != null) {
ConsoleLogger.info("Set Language to: " + lang);
return lang;
}
ConsoleLogger.info("Language file not found for " + lang + ", set to default language: en !");
return "en";
}
/** /**
* Method switchAntiBotMod. * Method switchAntiBotMod.
* *
@ -337,20 +281,13 @@ public final class Settings {
} }
/** /**
* Saves current configuration (plus defaults) to disk. * Load the value via the new Property setup for temporary support within this old settings manager.
* <p>
* If defaults and configuration are empty, saves blank file.
* *
* @return True if saved successfully * @param property The property to load
* @param <T> The property type
* @return The config value of the property
*/ */
private boolean saveDefaults() { private static <T> T load(Property<T> property) {
configFile.options() return property.getFromFile(configFile);
.copyDefaults(true)
.copyHeader(true);
boolean success = save();
configFile.options()
.copyDefaults(false)
.copyHeader(false);
return success;
} }
} }

View File

@ -13,6 +13,9 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import static fr.xephi.authme.settings.properties.RegistrationSettings.DELAY_JOIN_MESSAGE;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_JOIN_MESSAGE;
import static fr.xephi.authme.settings.properties.RegistrationSettings.REMOVE_LEAVE_MESSAGE;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS; import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS;
import static java.lang.String.format; import static java.lang.String.format;
@ -43,9 +46,12 @@ public final class SettingsMigrationService {
configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*"); configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*");
changes = true; changes = true;
} }
changes = changes || performMailTextToFileMigration(configuration, pluginFolder);
return changes; // Note ljacqu 20160211: Concatenating migration methods with | instead of the usual ||
// ensures that all migrations will be performed
return changes
| performMailTextToFileMigration(configuration, pluginFolder)
| migrateJoinLeaveMessages(configuration);
} }
@VisibleForTesting @VisibleForTesting
@ -61,8 +67,7 @@ public final class SettingsMigrationService {
private static boolean hasDeprecatedProperties(FileConfiguration configuration) { private static boolean hasDeprecatedProperties(FileConfiguration configuration) {
String[] deprecatedProperties = { String[] deprecatedProperties = {
"Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications", "Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications",
"Passpartu", "Performances", "settings.delayJoinMessage", "settings.restrictions.enablePasswordVerifier", "Passpartu", "Performances", "settings.restrictions.enablePasswordVerifier", "Xenoforo.predefinedSalt"};
"Xenoforo.predefinedSalt"};
for (String deprecatedPath : deprecatedProperties) { for (String deprecatedPath : deprecatedProperties) {
if (configuration.contains(deprecatedPath)) { if (configuration.contains(deprecatedPath)) {
return true; return true;
@ -104,6 +109,33 @@ public final class SettingsMigrationService {
return true; return true;
} }
/**
* Detect deprecated {@code settings.delayJoinLeaveMessages} and inform user of new "remove join messages"
* and "remove leave messages" settings.
*
* @param configuration The file configuration
* @return True if the configuration has changed, false otherwise
*/
private static boolean migrateJoinLeaveMessages(FileConfiguration configuration) {
final String oldDelayJoinPath = "settings.delayJoinLeaveMessages";
if (configuration.contains(oldDelayJoinPath)) {
ConsoleLogger.info("Detected deprecated property " + oldDelayJoinPath);
ConsoleLogger.info(String.format("Note that we now also have the settings %s and %s",
REMOVE_JOIN_MESSAGE.getPath(), REMOVE_LEAVE_MESSAGE.getPath()));
if (!configuration.contains(DELAY_JOIN_MESSAGE.getPath())) {
configuration.set(DELAY_JOIN_MESSAGE.getPath(), true);
ConsoleLogger.info("Renamed " + oldDelayJoinPath + " to " + DELAY_JOIN_MESSAGE.getPath());
}
return true;
}
return false;
}
// -------
// Utilities
// -------
/** /**
* Copy a resource file (from the JAR) to the given file if it doesn't exist. * Copy a resource file (from the JAR) to the given file if it doesn't exist.
* *

View File

@ -80,9 +80,17 @@ public class RegistrationSettings implements SettingsClass {
public static final Property<Boolean> BROADCAST_WELCOME_MESSAGE = public static final Property<Boolean> BROADCAST_WELCOME_MESSAGE =
newProperty("settings.broadcastWelcomeMessage", false); newProperty("settings.broadcastWelcomeMessage", false);
@Comment("Do we need to delay the join/leave message to be displayed only when the player is authenticated?") @Comment("Should we delay the join message and display it once the player has logged in?")
public static final Property<Boolean> DELAY_JOIN_LEAVE_MESSAGES = public static final Property<Boolean> DELAY_JOIN_MESSAGE =
newProperty("settings.delayJoinLeaveMessages", true); newProperty("settings.delayJoinMessage", false);
@Comment("Should we remove join messages altogether?")
public static final Property<Boolean> REMOVE_JOIN_MESSAGE =
newProperty("settings.removeJoinMessage", false);
@Comment("Should we remove leave messages?")
public static final Property<Boolean> REMOVE_LEAVE_MESSAGE =
newProperty("settings.removeLeaveMessage", false);
@Comment("Do we need to add potion effect Blinding before login/reigster?") @Comment("Do we need to add potion effect Blinding before login/reigster?")
public static final Property<Boolean> APPLY_BLIND_EFFECT = public static final Property<Boolean> APPLY_BLIND_EFFECT =

View File

@ -126,10 +126,18 @@ public class RestrictionSettings implements SettingsClass {
public static final Property<Boolean> ENABLE_PASSWORD_CONFIRMATION = public static final Property<Boolean> ENABLE_PASSWORD_CONFIRMATION =
newProperty("settings.restrictions.enablePasswordConfirmation", true); newProperty("settings.restrictions.enablePasswordConfirmation", true);
@Comment("Should we protect the player inventory before logging in?") @Comment("Should we protect the player inventory before logging in? Requires ProtocolLib.")
public static final Property<Boolean> PROTECT_INVENTORY_BEFORE_LOGIN = public static final Property<Boolean> PROTECT_INVENTORY_BEFORE_LOGIN =
newProperty("settings.restrictions.ProtectInventoryBeforeLogIn", true); newProperty("settings.restrictions.ProtectInventoryBeforeLogIn", true);
@Comment("Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.")
public static final Property<Boolean> DENY_TABCOMPLETE_BEFORE_LOGIN =
newProperty("settings.restrictions.DenyTabCompleteBeforeLogin", true);
@Comment("Should we hide the tablist before logging in? Requires ProtocolLib.")
public static final Property<Boolean> HIDE_TABLIST_BEFORE_LOGIN =
newProperty("settings.restrictions.HideTablistBeforeLogin", true);
@Comment({ @Comment({
"Should we display all other accounts from a player when he joins?", "Should we display all other accounts from a player when he joins?",
"permission: /authme.admin.accounts"}) "permission: /authme.admin.accounts"})

View File

@ -9,7 +9,6 @@ import java.util.List;
import static fr.xephi.authme.settings.domain.Property.newProperty; import static fr.xephi.authme.settings.domain.Property.newProperty;
import static fr.xephi.authme.settings.domain.PropertyType.STRING_LIST; import static fr.xephi.authme.settings.domain.PropertyType.STRING_LIST;
import static fr.xephi.authme.settings.domain.Property.newProperty;
public class SecuritySettings implements SettingsClass { public class SecuritySettings implements SettingsClass {

View File

@ -132,8 +132,12 @@ settings:
# when it's true, registration require that kind of command: # when it's true, registration require that kind of command:
# /register <password> <confirmPassword> # /register <password> <confirmPassword>
enablePasswordConfirmation: true enablePasswordConfirmation: true
# Should we protect the player inventory before logging in? # Should we protect the player inventory before logging in? Requires ProtocolLib.
ProtectInventoryBeforeLogIn: true ProtectInventoryBeforeLogIn: true
# Should we deny the tabcomplete feature before logging in? Requires ProtocolLib.
DenyTabCompleteBeforeLogin: true
# Should we hide the tablist before logging in? Requires ProtocolLib.
HideTablistBeforeLogin: true
# Should we display all other accounts from a player when he joins? # Should we display all other accounts from a player when he joins?
# permission: /authme.admin.accounts # permission: /authme.admin.accounts
displayOtherAccounts: true displayOtherAccounts: true
@ -186,7 +190,7 @@ settings:
# Example unLoggedinGroup: NotLogged # Example unLoggedinGroup: NotLogged
unLoggedinGroup: unLoggedinGroup unLoggedinGroup: unLoggedinGroup
# possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB, # possible values: MD5, SHA1, SHA256, WHIRLPOOL, XAUTH, MD5VB, PHPBB,
# MYBB, IPB3, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512, # MYBB, IPB3, IPB4, PHPFUSION, SMF, XENFORO, SALTED2MD5, JOOMLA, BCRYPT, WBB3, SHA512,
# DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only) # DOUBLEMD5, PBKDF2, PBKDF2DJANGO, WORDPRESS, ROYALAUTH, CUSTOM(for developpers only)
passwordHash: SHA256 passwordHash: SHA256
# salt length for the SALTED2MD5 MD5(MD5(password)+salt) # salt length for the SALTED2MD5 MD5(MD5(password)+salt)
@ -252,15 +256,19 @@ settings:
useWelcomeMessage: true useWelcomeMessage: true
# Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player # Do we need to broadcast the welcome message to all server or only to the player? set true for server or false for player
broadcastWelcomeMessage: false broadcastWelcomeMessage: false
# Do we need to delay the join/leave message to be displayed only when the player is authenticated ? # Should we delay the join message and display it once the player has logged in?
delayJoinLeaveMessages: true delayJoinMessage: true
# Should we remove join messages altogether?
removeJoinMessage: true
# Should we remove leave messages?
removeLeaveMessage: 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 with another case? # Do we need to prevent people to login with another case?
# If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI
preventOtherCase: false 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: ''
# MySQL column for the group, needed for some forum/cms support # MySQL column for the group, needed for some forum/cms support
mySQLColumnGroup: '' mySQLColumnGroup: ''
@ -275,7 +283,7 @@ ExternalBoardOptions:
bCryptLog2Round: 10 bCryptLog2Round: 10
# phpBB prefix defined during phpbb installation process # phpBB prefix defined during phpbb installation process
phpbbTablePrefix: 'phpbb_' phpbbTablePrefix: 'phpbb_'
# phpBB activated group id , 2 is default registered group defined by phpbb # phpBB activated group id, 2 is default registered group defined by phpbb
phpbbActivatedGroupId: 2 phpbbActivatedGroupId: 2
# WordPress prefix defined during WordPress installation process # WordPress prefix defined during WordPress installation process
wordpressTablePrefix: 'wp_' wordpressTablePrefix: 'wp_'

View File

@ -22,9 +22,6 @@ usage_unreg: '&cКоманда: /unregister парола'
pwd_changed: '&cПаролата е променена!' pwd_changed: '&cПаролата е променена!'
user_unknown: '&cПотребителя не е регистриран' user_unknown: '&cПотребителя не е регистриран'
password_error: '&fПаролата не съвпада' password_error: '&fПаролата не съвпада'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
invalid_session: '&cYour IP has been changed and your session data has expired!'
reg_only: '&fСамо за регистрирани! Моля посети http://example.com за регистрация' reg_only: '&fСамо за регистрирани! Моля посети http://example.com за регистрация'
logged_in: '&cВече сте влязъл!' logged_in: '&cВече сте влязъл!'
logout: '&cУспешен изход от регистрацията!' logout: '&cУспешен изход от регистрацията!'
@ -56,6 +53,3 @@ email_send: '[AuthMe] Изпраен е имейл !'
country_banned: Твоята държава е забранена в този сървър! country_banned: Твоята държава е забранена в този сървър!
antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично включен, открита е потенциална атака!' antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично включен, открита е потенциална атака!'
antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключване след %m Минути.' antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключване след %m Минути.'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -59,4 +59,4 @@ email_exists: '&cUm email de recuperação já foi enviado! Você pode reenviar
country_banned: '&4Seu país foi banido do servidor! Your country is banned from this server!' country_banned: '&4Seu país foi banido do servidor! Your country is banned from this server!'
antibot_auto_enabled: '&4[AntiBotService] AntiBot ativado devido ao grande número de conexões!' antibot_auto_enabled: '&4[AntiBotService] AntiBot ativado devido ao grande número de conexões!'
antibot_auto_disabled: '&2[AntiBotService] AntiBot desativado após %m minutos!' antibot_auto_disabled: '&2[AntiBotService] AntiBot desativado após %m minutos!'
two_factor_create: '&2Your secret code is %code' two_factor_create: '&2Seu código secreto é %code'

View File

@ -8,8 +8,6 @@ reg_disabled: '&cRegistrace je zakazana!'
valid_session: '&cAutomaticke znovuprihlaseni.' valid_session: '&cAutomaticke znovuprihlaseni.'
login: '&cUspesne prihlaseni!' login: '&cUspesne prihlaseni!'
user_regged: '&cUzivatelske jmeno je jiz registrovano.' user_regged: '&cUzivatelske jmeno je jiz registrovano.'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
usage_reg: '&cPouzij: "/register heslo heslo".' usage_reg: '&cPouzij: "/register heslo heslo".'
no_perm: '&cNemas opravneni.' no_perm: '&cNemas opravneni.'
error: '&cVyskytla se chyba - kontaktujte administratora ...' error: '&cVyskytla se chyba - kontaktujte administratora ...'
@ -55,6 +53,3 @@ email_send: '[AuthMe] Email pro obnoveni hesla odeslan!'
country_banned: 'Vase zeme je na tomto serveru zakazana' country_banned: 'Vase zeme je na tomto serveru zakazana'
antibot_auto_enabled: '[AuthMe] AntiBotMod automaticky spusten z duvodu masivnich pripojeni!' antibot_auto_enabled: '[AuthMe] AntiBotMod automaticky spusten z duvodu masivnich pripojeni!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automaticky ukoncen po %m minutach, doufejme v konec invaze' antibot_auto_disabled: '[AuthMe] AntiBotMod automaticky ukoncen po %m minutach, doufejme v konec invaze'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -57,4 +57,4 @@ country_banned: '&4Dein Land ist gesperrt'
antibot_auto_enabled: '&4[AntiBotService] AntiBotMod wurde aufgrund hoher Netzauslastung automatisch aktiviert!' antibot_auto_enabled: '&4[AntiBotService] AntiBotMod wurde aufgrund hoher Netzauslastung automatisch aktiviert!'
antibot_auto_disabled: '&2[AntiBotService] AntiBotMod wurde nach %m Minuten deaktiviert, hoffentlich ist die Invasion vorbei' antibot_auto_disabled: '&2[AntiBotService] AntiBotMod wurde nach %m Minuten deaktiviert, hoffentlich ist die Invasion vorbei'
kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du dich mit dem Server verbindest' kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du dich mit dem Server verbindest'
two_factor_create: '&2Your secret code is %code' two_factor_create: '&2Dein geheimer Code ist %code'

View File

@ -8,8 +8,6 @@ wrong_pwd: '&cContraseña incorrecta'
unregistered: '&c¡Cuenta eliminada del registro!' unregistered: '&c¡Cuenta eliminada del registro!'
reg_disabled: '&cEl registro está desactivado' reg_disabled: '&cEl registro está desactivado'
valid_session: '&cInicio de sesión' valid_session: '&cInicio de sesión'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
login: '&c¡Sesión iniciada!' login: '&c¡Sesión iniciada!'
vb_nonActiv: '&fTu cuenta no está activada aún, ¡revisa tu correo!' vb_nonActiv: '&fTu cuenta no está activada aún, ¡revisa tu correo!'
user_regged: '&cUsuario ya registrado' user_regged: '&cUsuario ya registrado'
@ -39,7 +37,7 @@ regex: '&cTu usuario tiene carácteres no admitidos, los cuales son: REG_EX'
add_email: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail' add_email: '&cPor favor agrega tu e-mail con: /email add tuEmail confirmarEmail'
recovery_email: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery <tuEmail>' recovery_email: '&c¿Olvidaste tu contraseña? Por favor usa /email recovery <tuEmail>'
usage_captcha: '&cUso: /captcha <theCaptcha>' usage_captcha: '&cUso: /captcha <theCaptcha>'
wrong_captcha: '&cCaptcha incorrecto, please use : /captcha THE_CAPTCHA' wrong_captcha: '&cCaptcha incorrecto, por favor usa: /captcha THE_CAPTCHA'
valid_captcha: '&c¡ Captcha ingresado correctamente !' valid_captcha: '&c¡ Captcha ingresado correctamente !'
kick_forvip: '&cUn jugador VIP ha ingresado al servidor lleno!' kick_forvip: '&cUn jugador VIP ha ingresado al servidor lleno!'
kick_fullserver: '&cEl servidor está lleno, lo sentimos!' kick_fullserver: '&cEl servidor está lleno, lo sentimos!'
@ -56,6 +54,4 @@ email_send: '[AuthMe] Correo de recuperación enviado !'
country_banned: 'Tu país ha sido baneado de este servidor!' country_banned: 'Tu país ha sido baneado de este servidor!'
antibot_auto_enabled: '[AuthMe] AntiBotMod activado automáticamente debido a conexiones masivas!' antibot_auto_enabled: '[AuthMe] AntiBotMod activado automáticamente debido a conexiones masivas!'
antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automáticamente luego de %m minutos. Esperamos que haya terminado' antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automáticamente luego de %m minutos. Esperamos que haya terminado'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -21,9 +21,6 @@ usage_unreg: '&cErabili: /unregister password'
pwd_changed: '&cPasahitza aldatu duzu!' pwd_changed: '&cPasahitza aldatu duzu!'
user_unknown: '&cErabiltzailea ez dago erregistratuta' user_unknown: '&cErabiltzailea ez dago erregistratuta'
password_error: '&fPasahitzak ez datoz bat' password_error: '&fPasahitzak ez datoz bat'
password_error_nick: '&fYou can''t use your name as password, please choose another one'
password_error_unsafe: '&fThe chosen password is not safe, please choose another one'
invalid_session: '&fSession Dataes doesnt corrispond Plaese wait the end of session'
reg_only: '&fErregistratuako erabiltzaileak bakarrik! Mesedez bisitatu http://example.com erregistratzeko' reg_only: '&fErregistratuako erabiltzaileak bakarrik! Mesedez bisitatu http://example.com erregistratzeko'
logged_in: '&cDagoeneko saioa hasita!' logged_in: '&cDagoeneko saioa hasita!'
logout: '&cAtera zara' logout: '&cAtera zara'
@ -37,9 +34,6 @@ name_len: '&cZure erabiltzaile izena motzegia edo luzeegia da'
regex: '&cZure erabiltzaileak karaktere debekatuak ditu. Karaktere onartuak: REG_EX' regex: '&cZure erabiltzaileak karaktere debekatuak ditu. Karaktere onartuak: REG_EX'
add_email: '&cMesedez gehitu zure emaila : /email add yourEmail confirmEmail' add_email: '&cMesedez gehitu zure emaila : /email add yourEmail confirmEmail'
recovery_email: '&cPasahitza ahaztu duzu? Erabili /email recovery <zureemaila>' recovery_email: '&cPasahitza ahaztu duzu? Erabili /email recovery <zureemaila>'
usage_captcha: '&cYou need to type a captcha, please type: /captcha <theCaptcha>'
wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA'
valid_captcha: '&cYour captcha is valid !'
kick_forvip: '&cVIP erabiltzaile bat sartu da zerbitzaria beteta zegoenean!' kick_forvip: '&cVIP erabiltzaile bat sartu da zerbitzaria beteta zegoenean!'
kick_fullserver: '&cZerbitzaria beteta dago, Barkatu!' kick_fullserver: '&cZerbitzaria beteta dago, Barkatu!'
usage_email_add: '&fErabili: /email add <email> <confirmeEmail> ' usage_email_add: '&fErabili: /email add <email> <confirmeEmail> '
@ -52,9 +46,4 @@ email_added: '[AuthMe] Emaila gehitu duzu !'
email_confirm: '[AuthMe] Konfirmatu zure emaila !' email_confirm: '[AuthMe] Konfirmatu zure emaila !'
email_changed: '[AuthMe] Emaila aldatua!' email_changed: '[AuthMe] Emaila aldatua!'
email_send: '[AuthMe] Berreskuratze emaila bidalita !' email_send: '[AuthMe] Berreskuratze emaila bidalita !'
email_exists: '[AuthMe] An email already exists on your account. You can change it using the command below' country_banned: '[AuthMe] Zure herrialdea blokeatuta dago zerbitzari honetan'
country_banned: '[AuthMe]Zure herrialdea blokeatuta dago zerbitzari honetan'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes,hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
two_factor_create: '&2Your secret code is %code'

View File

@ -12,8 +12,6 @@ vb_nonActiv: '&fKäyttäjäsi ei ole vahvistettu!'
user_regged: '&cPelaaja on jo rekisteröity' user_regged: '&cPelaaja on jo rekisteröity'
usage_reg: '&cKäyttötapa: /register salasana salasana' usage_reg: '&cKäyttötapa: /register salasana salasana'
max_reg: '&fSinulla ei ole oikeuksia tehdä enempää pelaajatilejä!' max_reg: '&fSinulla ei ole oikeuksia tehdä enempää pelaajatilejä!'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
no_perm: '&cEi oikeuksia' no_perm: '&cEi oikeuksia'
error: '&fVirhe: Ota yhteys palveluntarjoojaan!' error: '&fVirhe: Ota yhteys palveluntarjoojaan!'
login_msg: '&cKirjaudu palvelimmelle komennolla "/login salasana"' login_msg: '&cKirjaudu palvelimmelle komennolla "/login salasana"'
@ -52,9 +50,3 @@ email_added: '[AuthMe] Sähköposti lisätty!'
email_confirm: '[AuthMe] Vahvistuta sähköposti!' email_confirm: '[AuthMe] Vahvistuta sähköposti!'
email_changed: '[AuthMe] Sähköposti vaihdettu!' email_changed: '[AuthMe] Sähköposti vaihdettu!'
email_send: '[AuthMe] Palautus sähköposti lähetetty!' email_send: '[AuthMe] Palautus sähköposti lähetetty!'
country_banned: 'Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes, hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -10,7 +10,7 @@ reg_disabled: '&cL''enregistrement est désactivé'
valid_session: '&cVous êtes authentifié' valid_session: '&cVous êtes authentifié'
login: '&cConnection effectuée!' login: '&cConnection effectuée!'
vb_nonActiv: '&fCe compte n''est pas actif, consultez vos emails!' vb_nonActiv: '&fCe compte n''est pas actif, consultez vos emails!'
user_regged: '&cCe nom est deja utilisé..' user_regged: '&cCe nom est deja utilisé.'
usage_reg: '&cUtilisez la commande /register motdepasse confirmermotdepasse' usage_reg: '&cUtilisez la commande /register motdepasse confirmermotdepasse'
max_reg: '&fLimite d''enregistrement atteinte pour ce compte' max_reg: '&fLimite d''enregistrement atteinte pour ce compte'
no_perm: '&cVous n''avez pas la permission' no_perm: '&cVous n''avez pas la permission'
@ -28,9 +28,9 @@ invalid_session: '&fSession invalide, relancez le jeu ou attendez la fin de la s
reg_only: '&fSeul les joueurs enregistré sont admis! Visite http://example.com' reg_only: '&fSeul les joueurs enregistré sont admis! Visite http://example.com'
logged_in: '&cVous êtes déjà connecté!' logged_in: '&cVous êtes déjà connecté!'
logout: '&cVous avez été déconnecté!' logout: '&cVous avez été déconnecté!'
same_nick: '&fUne personne ayant ce même pseudo joue déjà..' same_nick: '&fUne personne ayant ce même pseudo joue déjà.'
registered: '&cEnregistrement réussi avec succès!' registered: '&cEnregistrement réussi avec succès!'
pass_len: '&fVotre mot de passe n''est pas assez long..' pass_len: '&fVotre mot de passe n''est pas assez long.'
reload: '&fConfiguration et BDD relancé avec succès' reload: '&fConfiguration et BDD relancé avec succès'
timeout: '&fVous avez été expulsé car vous êtes trop lent pour vous enregistrer !' timeout: '&fVous avez été expulsé car vous êtes trop lent pour vous enregistrer !'
usage_changepassword: '&fPour changer de mot de passe, utilisez: /changepassword ancienmdp nouveaumdp' usage_changepassword: '&fPour changer de mot de passe, utilisez: /changepassword ancienmdp nouveaumdp'
@ -55,7 +55,7 @@ email_changed: '[AuthMe] Email changé !'
email_send: '[AuthMe] Email de récupération envoyé!' email_send: '[AuthMe] Email de récupération envoyé!'
country_banned: 'Votre pays est banni de ce serveur' country_banned: 'Votre pays est banni de ce serveur'
antibot_auto_enabled: '[AuthMe] AntiBotMod a été activé automatiquement à cause de nombreuses connections!' antibot_auto_enabled: '[AuthMe] AntiBotMod a été activé automatiquement à cause de nombreuses connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod a été désactivé automatiquement après %m Minutes, espérons que l''invasion soit arrêtée!' antibot_auto_disabled: '[AuthMe] AntiBotMod a été désactivé automatiquement après %m minutes, espérons que l''invasion soit arrêtée!'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' kick_antibot: 'AntiBotMod est activé ! Veuillez attendre quelques minutes avant de joindre le serveur.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' email_exists: '&cUn email de restauration a déjà été envoyé ! Vous pouvez le jeter et vous en faire envoyez un nouveau en utilisant :'
two_factor_create: '&2Your secret code is %code' two_factor_create: '&2Votre code secret est %code'

View File

@ -6,12 +6,10 @@ reg_voluntarily: '&fPodes rexistrar o teu nome no servidor co comando
usage_log: '&cUso: /login <contrasinal>' usage_log: '&cUso: /login <contrasinal>'
wrong_pwd: '&cContrasinal equivocado' wrong_pwd: '&cContrasinal equivocado'
unregistered: '&cFeito! Xa non estás rexistrado!' unregistered: '&cFeito! Xa non estás rexistrado!'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
reg_disabled: '&cO rexistro está deshabilitado' reg_disabled: '&cO rexistro está deshabilitado'
valid_session: '&cIdentificado mediante a sesión' valid_session: '&cIdentificado mediante a sesión'
login: '&cIdentificación con éxito!' login: '&cIdentificación con éxito!'
vb_nonActiv: '&fA t&uacute;a conta aínda non está activada, comproba a t&uacute;a bandexa de correo!!' vb_nonActiv: '&fA túa conta aínda non está activada, comproba a túa bandexa de correo!!'
user_regged: '&cEse nome de usuario xa está rexistrado' user_regged: '&cEse nome de usuario xa está rexistrado'
usage_reg: '&cUso: /register contrasinal confirmarContrasinal' usage_reg: '&cUso: /register contrasinal confirmarContrasinal'
max_reg: '&fExcediches o máximo de rexistros para a t&uacute;a Conta' max_reg: '&fExcediches o máximo de rexistros para a t&uacute;a Conta'
@ -57,6 +55,3 @@ country_banned: 'O teu país está bloqueado neste servidor'
antibot_auto_enabled: '[AuthMe] AntiBotMod conectouse automáticamente debido a conexións masivas!' antibot_auto_enabled: '[AuthMe] AntiBotMod conectouse automáticamente debido a conexións masivas!'
antibot_auto_disabled: '[AuthMe] AntiBotMod desactivouse automáticamente despois de %m minutos, antibot_auto_disabled: '[AuthMe] AntiBotMod desactivouse automáticamente despois de %m minutos,
esperemos que a invasión se detivera' esperemos que a invasión se detivera'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -57,4 +57,3 @@ country_banned: '&4Az országod tiltólistán van ezen a szerveren!'
antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt a nagy számú hálózati kapcsolat miatt!' antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt a nagy számú hálózati kapcsolat miatt!'
antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m múlva!' antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m múlva!'
kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérünk várj pár másodpercet a csatlakozáshoz.' kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérünk várj pár másodpercet a csatlakozáshoz.'
two_factor_create: '&2Your secret code is %code'

View File

@ -10,14 +10,12 @@ valid_session: '&2Otomatis login, karena sesi masih terhubung.'
login: '&2Login berhasil!' login: '&2Login berhasil!'
vb_nonActiv: '&cAkunmu belum diaktifkan, silahkan periksa email kamu!' vb_nonActiv: '&cAkunmu belum diaktifkan, silahkan periksa email kamu!'
user_regged: '&cKamu telah mendaftarkan username ini!' user_regged: '&cKamu telah mendaftarkan username ini!'
usage_reg: '&cUsage: /register <password> <ulangiPassword>'
max_reg: '&Kamu telah mencapai batas maksimum pendaftaran di server ini!' max_reg: '&Kamu telah mencapai batas maksimum pendaftaran di server ini!'
no_perm: '&4Kamu tidak mempunyai izin melakukan ini!' no_perm: '&4Kamu tidak mempunyai izin melakukan ini!'
error: '&4Terjadi kesalahan tak dikenal, silahkan hubungi Administrator!' error: '&4Terjadi kesalahan tak dikenal, silahkan hubungi Administrator!'
login_msg: '&cSilahkan login menggunakan command "/login <password>"' login_msg: '&cSilahkan login menggunakan command "/login <password>"'
reg_msg: '&3Silahkan mendaftar ke server menggunakan command "/register <password> <ulangiPassword>"' reg_msg: '&3Silahkan mendaftar ke server menggunakan command "/register <password> <ulangiPassword>"'
reg_email_msg: '&3Silahkan mendaftar ke server menggunakan command "/register <email> <ulangiEmail>"' reg_email_msg: '&3Silahkan mendaftar ke server menggunakan command "/register <email> <ulangiEmail>"'
usage_unreg: '&cUsage: /unregister <password>'
pwd_changed: '&2Berhasil mengubah password!' pwd_changed: '&2Berhasil mengubah password!'
user_unknown: '&cUser ini belum terdaftar!' user_unknown: '&cUser ini belum terdaftar!'
password_error: '&cPassword tidak cocok, silahkan periksa dan ulangi kembali!' password_error: '&cPassword tidak cocok, silahkan periksa dan ulangi kembali!'
@ -53,8 +51,5 @@ email_confirm: '&cSilahkan konfirmasi alamat email kamu!'
email_changed: '&2Alamat email telah diubah dengan benar!' email_changed: '&2Alamat email telah diubah dengan benar!'
email_send: '&2Email pemulihan akun telah dikirim! Silahkan periksa kotak masuk emailmu!' email_send: '&2Email pemulihan akun telah dikirim! Silahkan periksa kotak masuk emailmu!'
email_exists: '&cEmail pemulihan sudah dikirim! kamu bisa membatalkan dan mengirimkan yg baru dengan command dibawah:' email_exists: '&cEmail pemulihan sudah dikirim! kamu bisa membatalkan dan mengirimkan yg baru dengan command dibawah:'
country_banned: '&4Your country is banned from this server!'
antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak koneksi yg diterima!' antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak koneksi yg diterima!'
antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!' antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
two_factor_create: '&2Your secret code is %code'

View File

@ -12,8 +12,6 @@ unregistered: '&c성공적으로 탈퇴했습니다!'
reg_disabled: '&c가입이 비활성화 되어있습니다' reg_disabled: '&c가입이 비활성화 되어있습니다'
valid_session: '&c세션 로그인' valid_session: '&c세션 로그인'
login: '&c성공적인 접속입니다!' login: '&c성공적인 접속입니다!'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
vb_nonActiv: '&f당신의 계정은 아직 활성화되어있지 않습니다, 당신의 이메일을 확인해보세요!' vb_nonActiv: '&f당신의 계정은 아직 활성화되어있지 않습니다, 당신의 이메일을 확인해보세요!'
user_regged: '&c사용자이름은 이미 가입했습니다' user_regged: '&c사용자이름은 이미 가입했습니다'
usage_reg: '&c사용법: /register 비밀번호 비밀번호확인' usage_reg: '&c사용법: /register 비밀번호 비밀번호확인'
@ -60,5 +58,3 @@ email_exists: '[AuthMe] 당신의 계정에 이미 이메일이 존재합니다.
country_banned: '당신의 국가는 이 서버에서 차단당했습니다' country_banned: '당신의 국가는 이 서버에서 차단당했습니다'
antibot_auto_enabled: '[AuthMe] 봇차단모드가 연결 개수 때문에 자동적으로 활성화됩니다!' antibot_auto_enabled: '[AuthMe] 봇차단모드가 연결 개수 때문에 자동적으로 활성화됩니다!'
antibot_auto_disabled: '[AuthMe] 봇차단모드가 %m 분 후에 자동적으로 비활성화됩니다' antibot_auto_disabled: '[AuthMe] 봇차단모드가 %m 분 후에 자동적으로 비활성화됩니다'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
two_factor_create: '&2Your secret code is %code'

View File

@ -14,8 +14,6 @@ usage_reg: '&eNaudojimas: /register slaptazodis pakartotiSlaptazodi'
max_reg: '&cJus pasiekete maksimalu registraciju skaiciu.' max_reg: '&cJus pasiekete maksimalu registraciju skaiciu.'
no_perm: '&cNera leidimo' no_perm: '&cNera leidimo'
error: '&cAtsirado klaida, praneskite adminstratoriui.' error: '&cAtsirado klaida, praneskite adminstratoriui.'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
login_msg: '&ePrasome prisijungti: /login slaptazodis' login_msg: '&ePrasome prisijungti: /login slaptazodis'
reg_msg: '&ePrasome prisiregistruoti: /register slaptazodis pakartotiSlaptazodi' reg_msg: '&ePrasome prisiregistruoti: /register slaptazodis pakartotiSlaptazodi'
reg_email_msg: '&cPlease register with "/register <email> <confirmEmail>"' reg_email_msg: '&cPlease register with "/register <email> <confirmEmail>"'
@ -42,19 +40,3 @@ wrong_captcha: '&cNeteisinga Captcha, naudokite : /captcha THE_CAPTCHA'
valid_captcha: '&cJusu captcha Teisinga!' valid_captcha: '&cJusu captcha Teisinga!'
kick_forvip: '&cA VIP prisijunge i pilna serveri!' kick_forvip: '&cA VIP prisijunge i pilna serveri!'
kick_fullserver: '&cServeris yra pilnas, Atsiprasome.' kick_fullserver: '&cServeris yra pilnas, Atsiprasome.'
usage_email_add: '&fUsage: /email add <email> <confirmEmail> '
usage_email_change: '&fUsage: /email change <oldEmail> <newEmail> '
usage_email_recovery: '&fUsage: /email recovery <email>'
new_email_invalid: '[AuthMe] New email invalid!'
old_email_invalid: '[AuthMe] Old email invalid!'
email_invalid: '[AuthMe] Invalid Email'
email_added: '[AuthMe] Email Added !'
email_confirm: '[AuthMe] Confirm your Email !'
email_changed: '[AuthMe] Email Change !'
email_send: '[AuthMe] Recovery Email Send !'
country_banned: 'Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes, hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -54,7 +54,5 @@ email_send: '[AuthMe] Herstel E-mail Verzonden!'
country_banned: 'Jouw land is geband op deze server' country_banned: 'Jouw land is geband op deze server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatisch aangezet vanewge veel verbindingen!' antibot_auto_enabled: '[AuthMe] AntiBotMod automatisch aangezet vanewge veel verbindingen!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatisch uitgezet na %m minuten, hopelijk is de invasie gestopt' antibot_auto_disabled: '[AuthMe] AntiBotMod automatisch uitgezet na %m minuten, hopelijk is de invasie gestopt'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.' kick_antibot: 'AntiBot is aangezet! Wacht alsjeblieft enkele minuten voor je met de server verbindt.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:' two_factor_create: '&2Je geheime code is %code'
reg_email_msg: '&3Please, register to the server with the command "/register <email> <confirmEmail>"'
two_factor_create: '&2Your secret code is %code'

View File

@ -16,8 +16,6 @@ wrong_pwd: '&cNiepoprawne haslo'
logout: '&cPomyslnie wylogowany' logout: '&cPomyslnie wylogowany'
usage_unreg: '&cUzycie: /unregister haslo' usage_unreg: '&cUzycie: /unregister haslo'
registered: '&aPomyslnie zarejestrowany!' registered: '&aPomyslnie zarejestrowany!'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
unregistered: '&4Pomyslnie odrejestrowany!' unregistered: '&4Pomyslnie odrejestrowany!'
login: '&aHaslo zaakceptowane!' login: '&aHaslo zaakceptowane!'
no_perm: '&4Nie masz uprawnien' no_perm: '&4Nie masz uprawnien'
@ -52,9 +50,3 @@ email_added: '[AuthMe] Email dodany!'
email_confirm: '[AuthMe] Potwierdz swoj email!' email_confirm: '[AuthMe] Potwierdz swoj email!'
email_changed: '[AuthMe] Email zmieniony!' email_changed: '[AuthMe] Email zmieniony!'
email_send: '[AuthMe] Email z odzyskaniem wyslany!' email_send: '[AuthMe] Email z odzyskaniem wyslany!'
country_banned: 'Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes, hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -19,8 +19,6 @@ reg_msg: '&cPor favor registe-se com "/register password confirmePassword"'
reg_email_msg: '&ePor favor registe-se com "/register <email> <confirmarEmail>"' reg_email_msg: '&ePor favor registe-se com "/register <email> <confirmarEmail>"'
usage_unreg: '&cUse: /unregister password' usage_unreg: '&cUse: /unregister password'
pwd_changed: '&cPassword alterada!' pwd_changed: '&cPassword alterada!'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
user_unknown: '&cUsername não registado' user_unknown: '&cUsername não registado'
password_error: '&fAs passwords não coincidem' password_error: '&fAs passwords não coincidem'
invalid_session: '&fDados de sessão não correspondem. Por favor aguarde o fim da sessão' invalid_session: '&fDados de sessão não correspondem. Por favor aguarde o fim da sessão'
@ -56,6 +54,3 @@ email_send: 'Nova palavra-passe enviada para o seu email!'
country_banned: 'O seu país está banido deste servidor' country_banned: 'O seu país está banido deste servidor'
antibot_auto_enabled: '[AuthMe] AntiBotMod activado automaticamente devido a um aumento anormal de tentativas de ligação!' antibot_auto_enabled: '[AuthMe] AntiBotMod activado automaticamente devido a um aumento anormal de tentativas de ligação!'
antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automaticamente após %m minutos, esperamos que a invasão tenha parado' antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automaticamente após %m minutos, esperamos que a invasão tenha parado'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -2,7 +2,7 @@ unknown_user: '&fПользователь не найден в Базе Данн
unsafe_spawn: '&eВаше расположение перед выходом было опасным - вы перенесены на спавн' unsafe_spawn: '&eВаше расположение перед выходом было опасным - вы перенесены на спавн'
not_logged_in: '&c&lВы еще не вошли!' not_logged_in: '&c&lВы еще не вошли!'
reg_voluntarily: '&aЧтобы зарегистрироваться введите: &e&l/reg ПАРОЛЬ ПОВТОРАРОЛЯ' reg_voluntarily: '&aЧтобы зарегистрироваться введите: &e&l/reg ПАРОЛЬ ПОВТОРАРОЛЯ'
usage_log: '&eСинтаксис: &d/l ПАРОЛЬ &eили &d/login ПАРОЛЬ' usage_log: '&eСинтаксис: &d/login ПАРОЛЬ'
wrong_pwd: '&c&lНеправильный пароль!' wrong_pwd: '&c&lНеправильный пароль!'
unregistered: '&6Вы успешно удалили свой аккаунт!' unregistered: '&6Вы успешно удалили свой аккаунт!'
reg_disabled: '&c&lРегистрация отключена' reg_disabled: '&c&lРегистрация отключена'
@ -14,7 +14,7 @@ usage_reg: '&c&lИспользование: &e&l/reg ПАРОЛЬ ПОВТОР_
max_reg: '&c&lВы превысили макс количество регистраций на ваш IP' max_reg: '&c&lВы превысили макс количество регистраций на ваш IP'
no_perm: '&c&lНедостаточно прав' no_perm: '&c&lНедостаточно прав'
error: '&c&lПроизошла ошибка. Свяжитесь с администратором' error: '&c&lПроизошла ошибка. Свяжитесь с администратором'
login_msg: '&a&lАвторизация: &e&l/l ПАРОЛЬ' login_msg: '&a&lАвторизация: &e&l/login ПАРОЛЬ'
reg_msg: '&a&lРегистрация: &e&l/reg ПАРОЛЬ ПОВТОРАРОЛЯ' reg_msg: '&a&lРегистрация: &e&l/reg ПАРОЛЬ ПОВТОРАРОЛЯ'
password_error_nick: '&c&lВы не можете использовать ваш ник в роли пароля' password_error_nick: '&c&lВы не можете использовать ваш ник в роли пароля'
password_error_unsafe: '&c&lВы не можете использовать небезопасный пароль' password_error_unsafe: '&c&lВы не можете использовать небезопасный пароль'
@ -55,6 +55,3 @@ email_send: '[AuthMe] Письмо с инструкциями для восст
country_banned: 'Вход с IP-адресов вашей страны воспрещен на этом сервере' country_banned: 'Вход с IP-адресов вашей страны воспрещен на этом сервере'
antibot_auto_enabled: '&a[AuthMe] AntiBot-режим автоматически включен из-за большого количества входов!' antibot_auto_enabled: '&a[AuthMe] AntiBot-режим автоматически включен из-за большого количества входов!'
antibot_auto_disabled: '&a[AuthMe] AntiBot-режим автоматичски отключен после %m мин. Надеюсь атака закончилась' antibot_auto_disabled: '&a[AuthMe] AntiBot-режим автоматичски отключен после %m мин. Надеюсь атака закончилась'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -17,8 +17,6 @@ reg_msg: '&cZaregistruj sa príkazom "/register heslo zopakujHeslo"'
reg_email_msg: '&cPlease register with "/register <email> <confirmEmail>"' reg_email_msg: '&cPlease register with "/register <email> <confirmEmail>"'
timeout: '&fVyprsal cas na prihlásenie' timeout: '&fVyprsal cas na prihlásenie'
wrong_pwd: '&cZadal si zlé heslo' wrong_pwd: '&cZadal si zlé heslo'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
logout: '&cBol si úspesne odhláseny' logout: '&cBol si úspesne odhláseny'
usage_unreg: '&cPríkaz: /unregister heslo' usage_unreg: '&cPríkaz: /unregister heslo'
registered: '&cBol si úspesne zaregistrovany' registered: '&cBol si úspesne zaregistrovany'
@ -41,24 +39,4 @@ name_len: '&cTvoje meno je velmi krátke alebo dlhé'
regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX' regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX'
add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"' add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"'
recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery <tvojEmail>' recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery <tvojEmail>'
usage_captcha: '&cUsage: /captcha <theCaptcha>'
wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA'
valid_captcha: '&cYour captcha is valid !'
kick_forvip: '&cA VIP Player join the full server!'
kick_fullserver: '&cThe server is actually full, Sorry!'
usage_email_add: '&fUsage: /email add <email> <confirmEmail> '
usage_email_change: '&fUsage: /email change <oldEmail> <newEmail> '
usage_email_recovery: '&fUsage: /email recovery <email>'
new_email_invalid: '[AuthMe] New email invalid!'
old_email_invalid: '[AuthMe] Old email invalid!'
email_invalid: '[AuthMe] Invalid Email'
email_added: '[AuthMe] Email Added !'
email_confirm: '[AuthMe] Confirm your Email !'
email_changed: '[AuthMe] Email Change !'
email_send: '[AuthMe] Recovery Email Send !'
country_banned: 'Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes, hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -21,8 +21,6 @@ usage_unreg: '&cKullanimi: /unregister sifren'
pwd_changed: '&cSifreniz degisti!' pwd_changed: '&cSifreniz degisti!'
user_unknown: '&cBu kullaniciyla kaydolunmamis!' user_unknown: '&cBu kullaniciyla kaydolunmamis!'
password_error: '&fSifren eslesmiyor' password_error: '&fSifren eslesmiyor'
password_error_nick: '&fYou can''t use your name as password, please choose another one'
password_error_unsafe: '&fThe chosen password is not safe, please choose another one'
invalid_session: '&fOturum veritabanlari uyusmuyor lutfen sonunu bekleyin' invalid_session: '&fOturum veritabanlari uyusmuyor lutfen sonunu bekleyin'
reg_only: '&fSadece kayitli uyeler girebilir ! Kayit olmak icin www.orneksite.com adresini ziyaret ediniz !' reg_only: '&fSadece kayitli uyeler girebilir ! Kayit olmak icin www.orneksite.com adresini ziyaret ediniz !'
logged_in: '&cZaten Giris Yapilmis!' logged_in: '&cZaten Giris Yapilmis!'
@ -52,9 +50,6 @@ email_added: '[AuthMe] Eposta Eklendi !'
email_confirm: '[AuthMe] Epostani Dogrula !' email_confirm: '[AuthMe] Epostani Dogrula !'
email_changed: '[AuthMe] Eposta Degistirildi !' email_changed: '[AuthMe] Eposta Degistirildi !'
email_send: '[AuthMe] Kurtarma postasi gonderildi !' email_send: '[AuthMe] Kurtarma postasi gonderildi !'
email_exists: '[AuthMe] An email already exists on your account. You can change it using the command below'
country_banned: 'Ulken bu serverdan banlandi !' country_banned: 'Ulken bu serverdan banlandi !'
antibot_auto_enabled: '[AuthMe] AntiBotMode otomatik olarak etkinlestirildi!' antibot_auto_enabled: '[AuthMe] AntiBotMode otomatik olarak etkinlestirildi!'
antibot_auto_disabled: '[AuthMe] AntiBotMode %m dakika sonra otomatik olarak isgal yuzundan devredisi birakildi' antibot_auto_disabled: '[AuthMe] AntiBotMode %m dakika sonra otomatik olarak isgal yuzundan devredisi birakildi'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
two_factor_create: '&2Your secret code is %code'

View File

@ -55,6 +55,3 @@ email_send: '[AuthMe] Лист для відновлення надіслано
country_banned: 'Сервер не доступний для вашої країни | Your country is banned from this server' country_banned: 'Сервер не доступний для вашої країни | Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично увімкнений (забагато одначасних з`єднань)!' antibot_auto_enabled: '[AuthMe] AntiBotMod автоматично увімкнений (забагато одначасних з`єднань)!'
antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично вимкнувся, сподіваємось атака зупинена' antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично вимкнувся, сподіваємось атака зупинена'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -53,8 +53,3 @@ email_send: '[AuthMe] Đã gửi email khôi phục mật khẩu tới bạn !'
country_banned: 'Rất tiếc, quốc gia của bạn không được phép gia nhập server' country_banned: 'Rất tiếc, quốc gia của bạn không được phép gia nhập server'
antibot_auto_enabled: '[AuthMe] AntiBot đã được kích hoạt vì lượng người chơi kết nối vượt quá giới hạn!' antibot_auto_enabled: '[AuthMe] AntiBot đã được kích hoạt vì lượng người chơi kết nối vượt quá giới hạn!'
antibot_auto_disabled: '[AuthMe] AntiBot tự huỷ kích hoạt sau %m phút, hi vọng lượng kết nối sẽ giảm bớt' antibot_auto_disabled: '[AuthMe] AntiBot tự huỷ kích hoạt sau %m phút, hi vọng lượng kết nối sẽ giảm bớt'
password_error_nick: '&cYou can''t use your name as password, please choose another one...'
password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -59,4 +59,3 @@ email_send: '&8[&6用戶系統&8] 忘記密碼信件已寄出,請查收。'
country_banned: '&8[&6用戶系統&8] 本伺服器已停止對你的國家提供遊戲服務。' country_banned: '&8[&6用戶系統&8] 本伺服器已停止對你的國家提供遊戲服務。'
antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程序已因應現時大量不尋常的連線而啟用。' antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程序已因應現時大量不尋常的連線而啟用。'
antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程序檢查到不正常連接數已減少,並於 %m 分鐘後停止運作。' antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程序檢查到不正常連接數已減少,並於 %m 分鐘後停止運作。'
two_factor_create: '&2Your secret code is %code'

View File

@ -58,6 +58,4 @@ email_send: '&8[&6用戶系統&8] 忘記密碼信件已寄出,請查收。'
country_banned: '&8[&6用戶系統&8] 本伺服器已停止對你的國家提供遊戲服務。' country_banned: '&8[&6用戶系統&8] 本伺服器已停止對你的國家提供遊戲服務。'
antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程序已因應現時大量不尋常連線而啟用。' antibot_auto_enabled: '&8[&6用戶系統&8] 防止機械人程序已因應現時大量不尋常連線而啟用。'
antibot_auto_disabled: '&8[&6用戶系統&8] 不正常連接數已減少,防止機械人程序將於 %m 分鐘後停止。' antibot_auto_disabled: '&8[&6用戶系統&8] 不正常連接數已減少,防止機械人程序將於 %m 分鐘後停止。'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
two_factor_create: '&2Your secret code is %code'

View File

@ -59,5 +59,3 @@ email_exists: '&b【AuthMe】&6這個帳戶已經有設定電子郵件了'
country_banned: '&b【AuthMe】&6你所在的地區無法進入此伺服器' country_banned: '&b【AuthMe】&6你所在的地區無法進入此伺服器'
antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!' antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!'
antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉' antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
two_factor_create: '&2Your secret code is %code'

View File

@ -0,0 +1,28 @@
package fr.xephi.authme;
import java.io.File;
import java.net.URL;
/**
* AuthMe test utilities.
*/
public final class TestHelper {
private TestHelper() {
}
/**
* Return a {@link File} to a file in the JAR's resources (main or test).
*
* @param path The absolute path to the file
* @return The project file
*/
public static File getJarFile(String path) {
URL url = TestHelper.class.getResource(path);
if (url == null) {
throw new IllegalStateException("File '" + path + "' could not be loaded");
}
return new File(url.getFile());
}
}

View File

@ -14,7 +14,6 @@ import fr.xephi.authme.settings.domain.Property;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;

View File

@ -27,7 +27,8 @@ public final class ListenerConsistencyTest {
private static final Set<String> CANCELED_EXCEPTIONS = Sets.newHashSet("AuthMePlayerListener#onPlayerJoin", private static final Set<String> CANCELED_EXCEPTIONS = Sets.newHashSet("AuthMePlayerListener#onPlayerJoin",
"AuthMePlayerListener#onPreLogin", "AuthMePlayerListener#onPlayerLogin", "AuthMePlayerListener#onPreLogin", "AuthMePlayerListener#onPlayerLogin",
"AuthMePlayerListener#onPlayerQuit", "AuthMeServerListener#onPluginDisable", "AuthMePlayerListener#onPlayerQuit", "AuthMeServerListener#onPluginDisable",
"AuthMeServerListener#onServerPing", "AuthMeServerListener#onPluginEnable"); "AuthMeServerListener#onServerPing", "AuthMeServerListener#onPluginEnable",
"AuthMePlayerListener#onJoinMessage");
@Test @Test
public void shouldSetIgnoreCancelledToTrue() { public void shouldSetIgnoreCancelledToTrue() {

View File

@ -0,0 +1,43 @@
package fr.xephi.authme.output;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
import java.io.File;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Tests that the project's default language file contains a text for all message keys.
*/
public class MessagesFileConsistencyTest {
private static final String DEFAULT_MESSAGES_FILE = "/messages/messages_en.yml";
@Test
public void shouldHaveAllMessages() {
File file = TestHelper.getJarFile(DEFAULT_MESSAGES_FILE);
FileConfiguration configuration = YamlConfiguration.loadConfiguration(file);
for (MessageKey messageKey : MessageKey.values()) {
verifyHasMessage(messageKey, configuration);
}
}
private static void verifyHasMessage(MessageKey messageKey, FileConfiguration configuration) {
final String key = messageKey.getKey();
final String message = configuration.getString(key);
assertThat("Default messages file should have message for key '" + key + "'",
StringUtils.isEmpty(message), equalTo(false));
for (String tag : messageKey.getTags()) {
assertThat("The message for key '" + key + "' contains the tag '" + tag + "' in the default messages file",
message.contains(tag), equalTo(true));
}
}
}

View File

@ -1,6 +1,8 @@
package fr.xephi.authme.output; package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.util.WrapperMock; import fr.xephi.authme.util.WrapperMock;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -11,12 +13,13 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mockito; import org.mockito.Mockito;
import java.io.File; import java.io.File;
import java.net.URL; import java.util.logging.Logger;
import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -26,7 +29,8 @@ import static org.mockito.Mockito.verify;
*/ */
public class MessagesIntegrationTest { public class MessagesIntegrationTest {
private static final String YML_TEST_FILE = "messages_test.yml"; private static final String YML_TEST_FILE = "/messages_test.yml";
private static final String YML_DEFAULT_TEST_FILE = "/messages_default.yml";
private Messages messages; private Messages messages;
@BeforeClass @BeforeClass
@ -39,15 +43,15 @@ public class MessagesIntegrationTest {
* Loads the messages in the file {@code messages_test.yml} in the test resources folder. * Loads the messages in the file {@code messages_test.yml} in the test resources folder.
* The file does not contain all messages defined in {@link MessageKey} and its contents * The file does not contain all messages defined in {@link MessageKey} and its contents
* reflect various test cases -- not what the keys stand for. * reflect various test cases -- not what the keys stand for.
* <p>
* Similarly, the {@code messages_default.yml} from the test resources represents a default
* file that should contain all messages, but again, for testing, it just contains a few.
*/ */
@Before @Before
public void setUpMessages() { public void setUpMessages() {
URL url = getClass().getClassLoader().getResource(YML_TEST_FILE); File testFile = TestHelper.getJarFile(YML_TEST_FILE);
if (url == null) { File defaultFile = TestHelper.getJarFile(YML_DEFAULT_TEST_FILE);
throw new RuntimeException("File '" + YML_TEST_FILE + "' could not be loaded"); messages = new Messages(testFile, defaultFile);
}
messages = new Messages(new File(url.getFile()));
} }
@Test @Test
@ -101,20 +105,6 @@ public class MessagesIntegrationTest {
assertThat(message[0], equalTo("Apostrophes ' should be loaded correctly, don't you think?")); assertThat(message[0], equalTo("Apostrophes ' should be loaded correctly, don't you think?"));
} }
@Test
public void shouldReturnErrorForUnknownCode() {
// given
// The following is a key that is not defined in the test file
MessageKey key = MessageKey.UNREGISTERED_SUCCESS;
// when
String[] message = messages.retrieve(key);
// then
assertThat(message, arrayWithSize(1));
assertThat(message[0], startsWith("Error getting message with key '"));
}
@Test @Test
public void shouldSendMessageToPlayer() { public void shouldSendMessageToPlayer() {
// given // given
@ -176,25 +166,105 @@ public class MessagesIntegrationTest {
assertThat(message, equalTo("Use /captcha THE_CAPTCHA to solve the captcha")); assertThat(message, equalTo("Use /captcha THE_CAPTCHA to solve the captcha"));
} }
@Test(expected = RuntimeException.class) @Test
public void shouldThrowForInvalidReplacementCount() { public void shouldLogErrorForInvalidReplacementCount() {
// given // given
Logger logger = mock(Logger.class);
ConsoleLogger.setLogger(logger);
MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR; MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR;
// when // when
messages.send(mock(CommandSender.class), key, "rep", "rep2"); messages.send(mock(CommandSender.class), key, "rep", "rep2");
// then - expect exception // then
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger).warning(captor.capture());
assertThat(captor.getValue(), containsString("Invalid number of replacements"));
} }
@Test(expected = RuntimeException.class) @Test
public void shouldThrowForReplacementsOnKeyWithNoTags() { public void shouldThrowForReplacementsOnKeyWithNoTags() {
// given // given
Logger logger = mock(Logger.class);
ConsoleLogger.setLogger(logger);
MessageKey key = MessageKey.UNKNOWN_USER; MessageKey key = MessageKey.UNKNOWN_USER;
// when // when
messages.send(mock(CommandSender.class), key, "Replacement"); messages.send(mock(CommandSender.class), key, "Replacement");
// then - expect exception // then
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(logger).warning(captor.capture());
assertThat(captor.getValue(), containsString("Invalid number of replacements"));
}
@Test
public void shouldGetMessageFromDefaultFile() {
// given
// Key is only present in default file
MessageKey key = MessageKey.MUST_REGISTER_MESSAGE;
// when
String message = messages.retrieveSingle(key);
// then
assertThat(message, equalTo("Message from default file"));
}
@Test
public void shouldNotUseMessageFromDefaultFile() {
// given
// Key is present in both files
MessageKey key = MessageKey.WRONG_PASSWORD;
// when
String message = messages.retrieveSingle(key);
// then
assertThat(message, equalTo("§cWrong password!"));
}
@Test
public void shouldReturnErrorForMissingMessage() {
// given
// Key is not present in test file or default file
MessageKey key = MessageKey.TWO_FACTOR_CREATE;
// when
String message = messages.retrieveSingle(key);
// then
assertThat(message, containsString("Error retrieving message"));
}
@Test
public void shouldAllowNullAsDefaultFile() {
// given
Messages testMessages = new Messages(TestHelper.getJarFile(YML_TEST_FILE), null);
// Key not present in test file
MessageKey key = MessageKey.TWO_FACTOR_CREATE;
// when
String message = testMessages.retrieveSingle(key);
// then
assertThat(message, containsString("Error retrieving message"));
}
@Test
public void shouldLoadOtherFile() {
// given
MessageKey key = MessageKey.WRONG_PASSWORD;
// assumption: message comes back as defined in messages_test.yml
assumeThat(messages.retrieveSingle(key), equalTo("§cWrong password!"));
// when
messages.reload(TestHelper.getJarFile("/messages_test2.yml"));
// then
assertThat(messages.retrieveSingle(key), equalTo("test2 - wrong password"));
// check that default message handling still works
assertThat(messages.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE),
equalTo("Message from default file"));
} }
} }

View File

@ -44,6 +44,22 @@ public class RandomStringTest {
} }
} }
@Test
public void shouldGenerateRandomLowerUpperString() {
// given
int[] lengths = {0, 1, 17, 143, 1808};
Pattern badChars = Pattern.compile(".*[^0-9a-zA-Z].*");
// when / then
for (int length : lengths) {
String result = RandomString.generateHex(length);
assertThat("Result '" + result + "' should have length " + length,
result.length(), equalTo(length));
assertThat("Result '" + result + "' should only have characters a-z, A-Z, 0-9",
badChars.matcher(result).matches(), equalTo(false));
}
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void shouldThrowForInvalidLength() { public void shouldThrowForInvalidLength() {
// given/when // given/when

View File

@ -0,0 +1,26 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.util.WrapperMock;
import org.junit.BeforeClass;
/**
* Test for {@link IPB4}.
*/
public class IPB4Test extends AbstractEncryptionMethodTest {
@BeforeClass
public static void setUpSettings() {
WrapperMock.createInstance();
ConsoleLoggerTestInitializer.setupLogger();
}
public IPB4Test() {
super(new IPB4(),
new HashedPassword("$2a$13$leEvXu77OIwPwNvtZIJvaeAx8EItGHuR3nIlq8416g0gXeJaQdrr2", "leEvXu77OIwPwNvtZIJval"), //password
new HashedPassword("$2a$13$xyTTP9zhQQtRRKIJPv5AuuOGJ6Ni9FLbDhcuIAcPjt3XzCxIWe3Uu", "xyTTP9zhQQtRRKIJPv5Au3"), //PassWord1
new HashedPassword("$2a$13$rGBrqErm9DZyzbxIGHlgf.xfA15/4d5Ay/TK.3y9lG3AljcoG9Lsi", "rGBrqErm9DZyzbxIGHlgfN"), //&^%te$t?Pw@_
new HashedPassword("$2a$13$18dKXZLoGpeHHL81edM9HuipiUcMjn5VDJHlxwRUMRXfJ1b.ZQrJ.", "18dKXZLoGpeHHL81edM9H6")); //âË_3(íù*
}
}

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.settings; package fr.xephi.authme.settings;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.settings.propertymap.PropertyMap;
@ -32,8 +33,7 @@ public class ConfigFileConsistencyTest {
@Test @Test
public void shouldHaveAllConfigs() throws IOException { public void shouldHaveAllConfigs() throws IOException {
// given // given
URL url = this.getClass().getResource(CONFIG_FILE); File configFile = TestHelper.getJarFile(CONFIG_FILE);
File configFile = new File(url.getFile());
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
// when // when

View File

@ -12,12 +12,12 @@ import org.junit.Test;
import java.io.File; import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static fr.xephi.authme.TestHelper.getJarFile;
import static fr.xephi.authme.settings.domain.Property.newProperty; import static fr.xephi.authme.settings.domain.Property.newProperty;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -29,18 +29,18 @@ import static org.junit.Assume.assumeThat;
public class NewSettingIntegrationTest { public class NewSettingIntegrationTest {
/** File name of the sample config including all {@link TestConfiguration} values. */ /** File name of the sample config including all {@link TestConfiguration} values. */
private static final String COMPLETE_FILE = "config-sample-values.yml"; private static final String COMPLETE_FILE = "/config-sample-values.yml";
/** File name of the sample config missing certain {@link TestConfiguration} values. */ /** File name of the sample config missing certain {@link TestConfiguration} values. */
private static final String INCOMPLETE_FILE = "config-incomplete-sample.yml"; private static final String INCOMPLETE_FILE = "/config-incomplete-sample.yml";
/** File name for testing difficult values. */ /** File name for testing difficult values. */
private static final String DIFFICULT_FILE = "config-difficult-values.yml"; private static final String DIFFICULT_FILE = "/config-difficult-values.yml";
private static PropertyMap propertyMap = generatePropertyMap(); private static PropertyMap propertyMap = generatePropertyMap();
@Test @Test
public void shouldLoadAndReadAllProperties() { public void shouldLoadAndReadAllProperties() {
// given // given
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(getConfigFile(COMPLETE_FILE)); YamlConfiguration configuration = YamlConfiguration.loadConfiguration(getJarFile(COMPLETE_FILE));
File file = new File("unused"); File file = new File("unused");
// when / then // when / then
@ -67,7 +67,7 @@ public class NewSettingIntegrationTest {
@Test @Test
public void shouldWriteMissingProperties() { public void shouldWriteMissingProperties() {
// given/when // given/when
File file = getConfigFile(INCOMPLETE_FILE); File file = getJarFile(INCOMPLETE_FILE);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file); YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
assumeThat(configuration.contains(TestConfiguration.BORING_COLORS.getPath()), equalTo(false)); assumeThat(configuration.contains(TestConfiguration.BORING_COLORS.getPath()), equalTo(false));
// Expectation: File is rewritten to since it does not have all configurations // Expectation: File is rewritten to since it does not have all configurations
@ -100,7 +100,7 @@ public class NewSettingIntegrationTest {
@Test @Test
public void shouldProperlyExportAnyValues() { public void shouldProperlyExportAnyValues() {
// given // given
File file = getConfigFile(DIFFICULT_FILE); File file = getJarFile(DIFFICULT_FILE);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file); YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
assumeThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(false)); assumeThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(false));
@ -147,19 +147,6 @@ public class NewSettingIntegrationTest {
} }
} }
/**
* Return a {@link File} instance to an existing file in the target/test-classes folder.
*
* @return The generated File
*/
private File getConfigFile(String file) {
URL url = getClass().getClassLoader().getResource(file);
if (url == null) {
throw new IllegalStateException("File '" + file + "' could not be loaded");
}
return new File(url.getFile());
}
/** /**
* Generate a property map with all properties in {@link TestConfiguration}. * Generate a property map with all properties in {@link TestConfiguration}.
* *

View File

@ -3,7 +3,6 @@ package fr.xephi.authme.settings;
import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.TestConfiguration; import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum; import fr.xephi.authme.settings.properties.TestEnum;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test; import org.junit.Test;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
@ -13,6 +12,8 @@ import java.io.File;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyDouble; import static org.mockito.Matchers.anyDouble;
@ -30,19 +31,19 @@ public class NewSettingTest {
@Test @Test
public void shouldLoadAllConfigs() { public void shouldLoadAllConfigs() {
// given // given
YamlConfiguration file = mock(YamlConfiguration.class); YamlConfiguration configuration = mock(YamlConfiguration.class);
given(file.getString(anyString(), anyString())).willAnswer(withDefaultArgument()); given(configuration.getString(anyString(), anyString())).willAnswer(withDefaultArgument());
given(file.getBoolean(anyString(), anyBoolean())).willAnswer(withDefaultArgument()); given(configuration.getBoolean(anyString(), anyBoolean())).willAnswer(withDefaultArgument());
given(file.getDouble(anyString(), anyDouble())).willAnswer(withDefaultArgument()); given(configuration.getDouble(anyString(), anyDouble())).willAnswer(withDefaultArgument());
given(file.getInt(anyString(), anyInt())).willAnswer(withDefaultArgument()); given(configuration.getInt(anyString(), anyInt())).willAnswer(withDefaultArgument());
setReturnValue(file, TestConfiguration.VERSION_NUMBER, 20); setReturnValue(configuration, TestConfiguration.VERSION_NUMBER, 20);
setReturnValue(file, TestConfiguration.SKIP_BORING_FEATURES, true); setReturnValue(configuration, TestConfiguration.SKIP_BORING_FEATURES, true);
setReturnValue(file, TestConfiguration.RATIO_ORDER, TestEnum.THIRD); setReturnValue(configuration, TestConfiguration.RATIO_ORDER, TestEnum.THIRD);
setReturnValue(file, TestConfiguration.SYSTEM_NAME, "myTestSys"); setReturnValue(configuration, TestConfiguration.SYSTEM_NAME, "myTestSys");
// when / then // when / then
NewSetting settings = new NewSetting(file, new File("conf.txt"), (PropertyMap) null); NewSetting settings = new NewSetting(configuration, null, null);
assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20)); assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20));
assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true)); assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true));
@ -54,6 +55,20 @@ public class NewSettingTest {
assertDefaultValue(TestConfiguration.COOL_OPTIONS, settings); assertDefaultValue(TestConfiguration.COOL_OPTIONS, settings);
} }
@Test
public void shouldReturnDefaultFile() {
// given
YamlConfiguration configuration = mock(YamlConfiguration.class);
NewSetting settings = new NewSetting(configuration, null, null);
// when
File defaultFile = settings.getDefaultMessagesFile();
// then
assertThat(defaultFile, not(nullValue()));
assertThat(defaultFile.exists(), equalTo(true));
}
private static <T> void setReturnValue(YamlConfiguration config, Property<T> property, T value) { private static <T> void setReturnValue(YamlConfiguration config, Property<T> property, T value) {
if (value instanceof String) { if (value instanceof String) {
when(config.getString(eq(property.getPath()), anyString())).thenReturn((String) value); when(config.getString(eq(property.getPath()), anyString())).thenReturn((String) value);

View File

@ -0,0 +1,66 @@
package fr.xephi.authme.settings;
import com.google.common.io.Files;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
/**
* Test for {@link SettingsMigrationService}.
*/
public class SettingsMigrationServiceTest {
@Rule
public TemporaryFolder testFolderHandler = new TemporaryFolder();
private File testFolder;
private File configTestFile;
/**
* Ensure that AuthMe regards the JAR's own config.yml as complete.
* If something legitimately needs migrating, a test from {@link ConfigFileConsistencyTest} should fail.
* If none fails in that class, it means something is wrong with the migration service
* as it wants to perform a migration on our up-to-date config.yml.
*/
@Test
public void shouldNotRewriteJarConfig() throws IOException {
// given
copyConfigToTestFolder();
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configTestFile);
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
assumeThat(testFolder.listFiles(), arrayWithSize(1));
// when
boolean result = SettingsMigrationService.checkAndMigrate(configuration, propertyMap, testFolder);
// then
assertThat(result, equalTo(false));
assertThat(testFolder.listFiles(), arrayWithSize(1));
}
private void copyConfigToTestFolder() throws IOException {
testFolder = testFolderHandler.newFolder("migrationtest");
final File testConfig = testFolderHandler.newFile("migrationtest/config.yml");
final File realConfig = TestHelper.getJarFile("/config.yml");
Files.copy(realConfig, testConfig);
if (!testConfig.exists()) {
throw new IOException("Could not copy project's config.yml to test folder");
}
configTestFile = testConfig;
}
}

View File

@ -0,0 +1,5 @@
# Simulates a default file
wrong_pwd: 'This message is overridden in messages_test.yml'
reg_only: 'Message from default file'
logged_in: '&cYou''re already logged in!'

View File

@ -1,3 +1,5 @@
# Sample messages file
unknown_user: 'This test message&nincludes&nsome new lines' unknown_user: 'This test message&nincludes&nsome new lines'
unsafe_spawn: '&cHere we have&bdefined some colors &dand some other &lthings' unsafe_spawn: '&cHere we have&bdefined some colors &dand some other &lthings'
not_logged_in: 'Apostrophes '' should be loaded correctly, don''t you think?' not_logged_in: 'Apostrophes '' should be loaded correctly, don''t you think?'

View File

@ -0,0 +1,6 @@
# Sample messages file
unknown_user: 'Message from test2'
unsafe_spawn: 'test2 - unsafe spawn'
not_logged_in: 'test2 - not logged in'
wrong_pwd: 'test2 - wrong password'