#1141 Make 2fa messages translatable, various cleanups (null safety, ...)

This commit is contained in:
ljacqu 2018-03-21 23:56:13 +01:00
parent 584a0bebbf
commit e9ab82db6b
10 changed files with 78 additions and 28 deletions

View File

@ -4,10 +4,9 @@ import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey; import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.security.totp.GenerateTotpService; import fr.xephi.authme.security.totp.GenerateTotpService;
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
import fr.xephi.authme.service.CommonService;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import javax.inject.Inject; import javax.inject.Inject;
@ -25,17 +24,19 @@ public class AddTotpCommand extends PlayerCommand {
private DataSource dataSource; private DataSource dataSource;
@Inject @Inject
private CommonService commonService; private Messages messages;
@Override @Override
protected void runCommand(Player player, List<String> arguments) { protected void runCommand(Player player, List<String> arguments) {
PlayerAuth auth = dataSource.getAuth(player.getName()); PlayerAuth auth = dataSource.getAuth(player.getName());
if (auth.getTotpKey() == null) { if (auth == null) {
messages.send(player, MessageKey.REGISTER_MESSAGE);
} else if (auth.getTotpKey() == null) {
TotpGenerationResult createdTotpInfo = generateTotpService.generateTotpKey(player); TotpGenerationResult createdTotpInfo = generateTotpService.generateTotpKey(player);
commonService.send(player, MessageKey.TWO_FACTOR_CREATE, messages.send(player, MessageKey.TWO_FACTOR_CREATE,
createdTotpInfo.getTotpKey(), createdTotpInfo.getAuthenticatorQrCodeUrl()); createdTotpInfo.getTotpKey(), createdTotpInfo.getAuthenticatorQrCodeUrl());
} else { } else {
player.sendMessage(ChatColor.RED + "Two-factor authentication is already enabled for your account!"); messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
} }
} }
} }

View File

@ -1,7 +1,10 @@
package fr.xephi.authme.command.executable.totp; package fr.xephi.authme.command.executable.totp;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.security.totp.GenerateTotpService; import fr.xephi.authme.security.totp.GenerateTotpService;
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -20,21 +23,29 @@ public class ConfirmTotpCommand extends PlayerCommand {
@Inject @Inject
private DataSource dataSource; private DataSource dataSource;
@Inject
private Messages messages;
@Override @Override
protected void runCommand(Player player, List<String> arguments) { protected void runCommand(Player player, List<String> arguments) {
// TODO #1141: Check if player already has TOTP PlayerAuth auth = dataSource.getAuth(player.getName());
if (auth == null) {
messages.send(player, MessageKey.REGISTER_MESSAGE);
} else if (auth.getTotpKey() != null) {
messages.send(player, MessageKey.TWO_FACTOR_ALREADY_ENABLED);
}
final TotpGenerationResult totpDetails = generateTotpService.getGeneratedTotpKey(player); final TotpGenerationResult totpDetails = generateTotpService.getGeneratedTotpKey(player);
if (totpDetails == null) { if (totpDetails == null) {
player.sendMessage("No TOTP key has been generated for you or it has expired. Please run /totp add"); messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_NO_CODE);
} else { } else {
boolean isCodeValid = generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, arguments.get(0)); boolean isCodeValid = generateTotpService.isTotpCodeCorrectForGeneratedTotpKey(player, arguments.get(0));
if (isCodeValid) { if (isCodeValid) {
generateTotpService.removeGenerateTotpKey(player); generateTotpService.removeGenerateTotpKey(player);
dataSource.setTotpKey(player.getName(), totpDetails.getTotpKey()); dataSource.setTotpKey(player.getName(), totpDetails.getTotpKey());
player.sendMessage("Successfully enabled two-factor authentication for your account"); messages.send(player, MessageKey.TWO_FACTOR_ENABLE_SUCCESS);
} else { } else {
player.sendMessage("Wrong code or code has expired. Please use /totp add again"); messages.send(player, MessageKey.TWO_FACTOR_ENABLE_ERROR_WRONG_CODE);
} }
} }
} }

View File

@ -3,6 +3,8 @@ package fr.xephi.authme.command.executable.totp;
import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.message.Messages;
import fr.xephi.authme.security.totp.TotpService; import fr.xephi.authme.security.totp.TotpService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -20,17 +22,20 @@ public class RemoveTotpCommand extends PlayerCommand {
@Inject @Inject
private TotpService totpService; private TotpService totpService;
@Inject
private Messages messages;
@Override @Override
protected void runCommand(Player player, List<String> arguments) { protected void runCommand(Player player, List<String> arguments) {
PlayerAuth auth = dataSource.getAuth(player.getName()); PlayerAuth auth = dataSource.getAuth(player.getName());
if (auth.getTotpKey() == null) { if (auth.getTotpKey() == null) {
player.sendMessage("Two-factor authentication is not enabled for your account!"); messages.send(player, MessageKey.TWO_FACTOR_NOT_ENABLED_ERROR);
} else { } else {
if (totpService.verifyCode(auth, arguments.get(0))) { if (totpService.verifyCode(auth, arguments.get(0))) {
dataSource.removeTotpKey(auth.getNickname()); dataSource.removeTotpKey(auth.getNickname());
player.sendMessage("Successfully removed two-factor authentication from your account"); messages.send(player, MessageKey.TWO_FACTOR_REMOVED_SUCCESS);
} else { } else {
player.sendMessage("Invalid code!"); messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
} }
} }
} }

View File

@ -53,20 +53,19 @@ public class TotpCodeCommand extends PlayerCommand {
} }
LimboPlayer limbo = limboService.getLimboPlayer(player.getName()); LimboPlayer limbo = limboService.getLimboPlayer(player.getName());
if (limbo.getState() == LimboPlayerState.TOTP_REQUIRED) { if (limbo != null && limbo.getState() == LimboPlayerState.TOTP_REQUIRED) {
processCode(player, limbo, auth, arguments.get(0)); processCode(player, auth, arguments.get(0));
} else { } else {
messages.send(player, MessageKey.LOGIN_MESSAGE); messages.send(player, MessageKey.LOGIN_MESSAGE);
} }
} }
private void processCode(Player player, LimboPlayer limbo, PlayerAuth auth, String inputCode) { private void processCode(Player player, PlayerAuth auth, String inputCode) {
boolean isCodeValid = totpService.verifyCode(auth, inputCode); boolean isCodeValid = totpService.verifyCode(auth, inputCode);
if (isCodeValid) { if (isCodeValid) {
limbo.setState(LimboPlayerState.FINISHED);
asynchronousLogin.performLogin(player, auth); asynchronousLogin.performLogin(player, auth);
} else { } else {
player.sendMessage("Invalid code!"); messages.send(player, MessageKey.TWO_FACTOR_INVALID_CODE);
} }
} }
} }

View File

@ -4,8 +4,6 @@ public enum LimboPlayerState {
PASSWORD_REQUIRED, PASSWORD_REQUIRED,
TOTP_REQUIRED, TOTP_REQUIRED
FINISHED
} }

View File

@ -195,11 +195,32 @@ public enum MessageKey {
EMAIL_ALREADY_USED_ERROR("email.already_used"), EMAIL_ALREADY_USED_ERROR("email.already_used"),
/** Your secret code is %code. You can scan it from here %url */ /** Your secret code is %code. You can scan it from here %url */
TWO_FACTOR_CREATE("misc.two_factor_create", "%code", "%url"), TWO_FACTOR_CREATE("two_factor.code_created", "%code", "%url"),
/** Please submit your two-factor authentication code with /2fa code &ltcode&gt;. */ /** Please submit your two-factor authentication code with /2fa code &ltcode&gt;. */
TWO_FACTOR_CODE_REQUIRED("two_factor.code_required"), TWO_FACTOR_CODE_REQUIRED("two_factor.code_required"),
/** Two-factor authentication is already enabled for your account! */
TWO_FACTOR_ALREADY_ENABLED("two_factor.already_enabled"),
/** No 2fa key has been generated for you or it has expired. Please run /2fa add */
TWO_FACTOR_ENABLE_ERROR_NO_CODE("two_factor.enable_error_no_code"),
/** Successfully enabled two-factor authentication for your account */
TWO_FACTOR_ENABLE_SUCCESS("two_factor.enable_success"),
/** Wrong code or code has expired. Please run /2fa add */
TWO_FACTOR_ENABLE_ERROR_WRONG_CODE("two_factor.enable_error_wrong_code"),
/** Two-factor authentication is not enabled for your account. Run /2fa add */
TWO_FACTOR_NOT_ENABLED_ERROR("two_factor.not_enabled_error"),
/** Successfully removed two-factor auth from your account */
TWO_FACTOR_REMOVED_SUCCESS("two_factor.removed_success"),
/** Invalid code! */
TWO_FACTOR_INVALID_CODE("two_factor.invalid_code"),
/** You are not the owner of this account. Please choose another name! */ /** You are not the owner of this account. Please choose another name! */
NOT_OWNER_ERROR("on_join_validation.not_owner_error"), NOT_OWNER_ERROR("on_join_validation.not_owner_error"),

View File

@ -30,6 +30,13 @@ public class TotpAuthenticator {
this.bukkitService = bukkitService; this.bukkitService = bukkitService;
} }
/**
* Returns whether the given input code matches for the provided TOTP key.
*
* @param totpKey the key to check with
* @param inputCode the input code to verify
* @return true if code is valid, false otherwise
*/
public boolean checkCode(String totpKey, String inputCode) { public boolean checkCode(String totpKey, String inputCode) {
try { try {
Integer totpCode = Integer.valueOf(inputCode); Integer totpCode = Integer.valueOf(inputCode);

View File

@ -56,7 +56,6 @@ unregister:
misc: misc:
accounts_owned_self: 'You own %count accounts:' accounts_owned_self: 'You own %count accounts:'
accounts_owned_other: 'The player %name has %count accounts:' accounts_owned_other: 'The player %name has %count accounts:'
two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
account_not_activated: '&cYour account isn''t activated yet, please check your emails!' account_not_activated: '&cYour account isn''t activated yet, please check your emails!'
password_changed: '&2Password changed successfully!' password_changed: '&2Password changed successfully!'
logout: '&2Logged out successfully!' logout: '&2Logged out successfully!'
@ -130,7 +129,15 @@ verification:
email_needed: '&3To verify your identity you need to link an email address with your account!!' email_needed: '&3To verify your identity you need to link an email address with your account!!'
two_factor: two_factor:
code_created: '&2Your secret code is %code. You can scan it from here %url'
code_required: 'Please submit your two-factor authentication code with /2fa code <code>' code_required: 'Please submit your two-factor authentication code with /2fa code <code>'
already_enabled: 'Two-factor authentication is already enabled for your account!'
enable_error_no_code: 'No 2fa key has been generated for you or it has expired. Please run /2fa add'
enable_success: 'Successfully enabled two-factor authentication for your account'
enable_error_wrong_code: 'Wrong code or code has expired. Please run /2fa add'
not_enabled_error: 'Two-factor authentication is not enabled for your account. Run /2fa add'
removed_success: 'Successfully removed two-factor auth from your account'
invalid_code: 'Invalid code!'
# Time units # Time units
time: time:

View File

@ -4,9 +4,9 @@ import com.warrenstrange.googleauth.IGoogleAuthenticator;
import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult; import fr.xephi.authme.security.totp.TotpAuthenticator.TotpGenerationResult;
import fr.xephi.authme.service.BukkitService; import fr.xephi.authme.service.BukkitService;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
@ -26,7 +26,6 @@ import static org.mockito.Mockito.verifyZeroInteractions;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class TotpAuthenticatorTest { public class TotpAuthenticatorTest {
@InjectMocks
private TotpAuthenticator totpAuthenticator; private TotpAuthenticator totpAuthenticator;
@Mock @Mock
@ -35,6 +34,11 @@ public class TotpAuthenticatorTest {
@Mock @Mock
private IGoogleAuthenticator googleAuthenticator; private IGoogleAuthenticator googleAuthenticator;
@Before
public void initializeTotpAuthenticator() {
totpAuthenticator = new TotpAuthenticator(googleAuthenticator, bukkitService);
}
@Test @Test
public void shouldGenerateTotpKey() { public void shouldGenerateTotpKey() {
// given // given

View File

@ -65,9 +65,6 @@ commands:
arg1: arg1:
label: loginArg label: loginArg
nonExistent: does not exist nonExistent: does not exist
arg2:
label: 2faArg
rhetorical: false
someProp: someProp:
label: '''someProp'' does not exist' label: '''someProp'' does not exist'
description: idk description: idk