Linked web users to players or console

PageExtension API:
- Added WebUser#getUsername
- Changed WebUser#getName to return player's name or 'console'
- API version 5.1-R0.4
This commit is contained in:
Risto Lahtela 2020-05-03 23:26:01 +03:00
parent 2f282dc7cc
commit ea2ae5d3e1
26 changed files with 464 additions and 150 deletions

View File

@ -7,7 +7,7 @@ dependencies {
compileOnly "com.google.code.gson:gson:$gsonVersion" compileOnly "com.google.code.gson:gson:$gsonVersion"
} }
ext.apiVersion = '5.1-R0.3' ext.apiVersion = '5.1-R0.4'
bintray { bintray {
user = System.getenv('BINTRAY_USER') user = System.getenv('BINTRAY_USER')

View File

@ -17,21 +17,34 @@
package com.djrapitops.plan.delivery.web.resolver.request; package com.djrapitops.plan.delivery.web.resolver.request;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public final class WebUser { public final class WebUser {
private final String name; private final String playerName;
private final String username;
private final Set<String> permissions; private final Set<String> permissions;
public WebUser(String name) { public WebUser(String playerName) {
this.name = name; this.playerName = playerName;
this.username = playerName;
this.permissions = new HashSet<>(); this.permissions = new HashSet<>();
} }
public WebUser(String name, String... permissions) { public WebUser(String playerName, String username, Collection<String> permissions) {
this(name); this.playerName = playerName;
this.username = username;
this.permissions = new HashSet<>(permissions);
}
/**
* @deprecated WebUser now has username and player name.
*/
@Deprecated
public WebUser(String playerName, String... permissions) {
this(playerName);
this.permissions.addAll(Arrays.asList(permissions)); this.permissions.addAll(Arrays.asList(permissions));
} }
@ -40,6 +53,10 @@ public final class WebUser {
} }
public String getName() { public String getName() {
return name; return playerName;
}
public String getUsername() {
return username;
} }
} }

View File

@ -0,0 +1,65 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.commands;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* Utility for managing command arguments.
*
* @author Rsl1122
*/
public class Arguments {
private final List<String> args;
public Arguments(String[] args) {
this.args = Arrays.asList(args);
}
public Arguments(List<String> args) {
this.args = args;
}
public Optional<String> get(int index) {
return index < args.size() ? Optional.of(args.get(index)) : Optional.empty();
}
public Optional<Integer> getInteger(int index) {
return get(index).map(Integer::parseInt);
}
public Optional<String> getAfter(String argumentIdentifier) {
for (int i = 0; i < args.size(); i++) {
String argument = args.get(i);
if (argumentIdentifier.equals(argument)) {
return get(i + 1);
}
}
return Optional.empty();
}
public boolean contains(String argument) {
return args.contains(argument);
}
public List<String> asList() {
return args;
}
}

View File

@ -16,11 +16,13 @@
*/ */
package com.djrapitops.plan.commands.subcommands; package com.djrapitops.plan.commands.subcommands;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.commands.Arguments;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.delivery.webserver.Addresses; import com.djrapitops.plan.delivery.webserver.Addresses;
import com.djrapitops.plan.delivery.webserver.auth.FailReason; import com.djrapitops.plan.delivery.webserver.auth.FailReason;
import com.djrapitops.plan.delivery.webserver.auth.RegistrationBin; import com.djrapitops.plan.delivery.webserver.auth.RegistrationBin;
import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.identification.UUIDUtility;
import com.djrapitops.plan.processing.Processing; import com.djrapitops.plan.processing.Processing;
import com.djrapitops.plan.settings.Permissions; import com.djrapitops.plan.settings.Permissions;
import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.Locale;
@ -39,13 +41,13 @@ import com.djrapitops.plugin.command.Sender;
import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.L;
import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.logging.error.ErrorHandler; import com.djrapitops.plugin.logging.error.ErrorHandler;
import com.djrapitops.plugin.utilities.Verify;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
/** /**
@ -65,6 +67,7 @@ public class RegisterCommand extends CommandNode {
private final Locale locale; private final Locale locale;
private final Processing processing; private final Processing processing;
private final DBSystem dbSystem; private final DBSystem dbSystem;
private final UUIDUtility uuidUtility;
private final Addresses addresses; private final Addresses addresses;
private final PluginLogger logger; private final PluginLogger logger;
private final ErrorHandler errorHandler; private final ErrorHandler errorHandler;
@ -75,15 +78,17 @@ public class RegisterCommand extends CommandNode {
Processing processing, Processing processing,
Addresses addresses, Addresses addresses,
DBSystem dbSystem, DBSystem dbSystem,
UUIDUtility uuidUtility,
PluginLogger logger, PluginLogger logger,
ErrorHandler errorHandler ErrorHandler errorHandler
) { ) {
// No Permission Requirement // No Permission Requirement
super("register", "", CommandType.PLAYER_OR_ARGS); super("register", "", CommandType.ALL);
this.locale = locale; this.locale = locale;
this.processing = processing; this.processing = processing;
this.addresses = addresses; this.addresses = addresses;
this.uuidUtility = uuidUtility;
this.logger = logger; this.logger = logger;
this.dbSystem = dbSystem; this.dbSystem = dbSystem;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
@ -104,27 +109,23 @@ public class RegisterCommand extends CommandNode {
return; return;
} }
if (args.length < 1) { if (args.length == 0) {
throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 1, Arrays.toString(getArguments()))); String url = addresses.getMainAddress().orElseGet(() -> {
sender.sendMessage(locale.getString(CommandLang.NO_ADDRESS_NOTIFY));
return addresses.getFallbackLocalhostAddress();
}) + "/register";
String linkPrefix = locale.getString(CommandLang.LINK_PREFIX);
sender.sendMessage(linkPrefix);
sender.sendLink(" ", locale.getString(CommandLang.LINK_CLICK_ME), url);
return;
} }
List<String> argumentList = Arrays.asList(args); Arguments arguments = new Arguments(args);
boolean newRegister = argumentList.contains("--code"); Optional<String> code = arguments.getAfter("--code");
if (newRegister) { if (code.isPresent()) {
if (CommandUtils.isPlayer(sender)) { registerUsingCode(sender, code.get());
register(argumentList, getPermissionLevel(sender), sender);
} else if (argumentList.contains("superuser")) {
register(argumentList, 0, sender);
} else {
sender.sendMessage("§cInvalid arguments.");
}
} else { } else {
// Legacy support registerUsingLegacy(sender, arguments);
if (CommandUtils.isPlayer(sender)) {
playerRegister(args, sender);
} else {
consoleRegister(args, sender, notEnoughArgsMsg);
}
} }
} catch (PassEncryptUtil.CannotPerformOperationException e) { } catch (PassEncryptUtil.CannotPerformOperationException e) {
errorHandler.log(L.WARN, this.getClass(), e); errorHandler.log(L.WARN, this.getClass(), e);
@ -138,43 +139,33 @@ public class RegisterCommand extends CommandNode {
} }
} }
private void consoleRegister(String[] args, Sender sender, String notEnoughArgsMsg) throws PassEncryptUtil.CannotPerformOperationException { public void registerUsingCode(Sender sender, String code) {
Verify.isTrue(args.length >= 3, () -> new IllegalArgumentException(notEnoughArgsMsg)); UUID linkedToUUID = CommandUtils.isPlayer(sender) ? uuidUtility.getUUIDOf(sender.getName()) : null;
Optional<User> user = RegistrationBin.register(code, linkedToUUID);
String userName = args[1]; if (user.isPresent()) {
Verify.isTrue(userName.length() <= 100, () -> new IllegalArgumentException("Username can only be 100 characters long.")); registerUser(user.get(), sender, getPermissionLevel(sender));
int permLevel = Integer.parseInt(args[2]); } else {
String passHash = PassEncryptUtil.createHash(args[0]);
registerUser(new WebUser(userName, passHash, permLevel), sender);
}
private void register(List<String> args, int permissionLevel, Sender sender) {
String code = "";
for (String arg : args) {
if (arg.length() == 12) code = arg;
}
if (code.isEmpty()) {
throw new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 1, "--code !<code>!"));
}
Optional<WebUser> user = RegistrationBin.register(code, permissionLevel);
if (!user.isPresent()) {
sender.sendMessage("§c" + locale.getString(FailReason.USER_DOES_NOT_EXIST)); sender.sendMessage("§c" + locale.getString(FailReason.USER_DOES_NOT_EXIST));
} else {
registerUser(user.get(), sender);
} }
} }
private void playerRegister(String[] args, Sender sender) throws PassEncryptUtil.CannotPerformOperationException { public void registerUsingLegacy(Sender sender, Arguments arguments) {
boolean registerSenderAsUser = args.length == 1; String password = arguments.get(0)
if (registerSenderAsUser) { .orElseThrow(() -> new IllegalArgumentException(locale.getString(CommandLang.FAIL_REQ_ARGS, 1, Arrays.toString(getArguments()))));
String user = sender.getName(); String passwordHash = PassEncryptUtil.createHash(password);
String pass = PassEncryptUtil.createHash(args[0]); int permissionLevel = arguments.getInteger(2)
int permLvl = getPermissionLevel(sender); .filter(arg -> sender.hasPermission(Permissions.MANAGE_WEB.getPerm())) // argument only allowed with plan.webmanage
registerUser(new WebUser(user, pass, permLvl), sender); .orElseGet(() -> getPermissionLevel(sender));
} else if (sender.hasPermission(Permissions.MANAGE_WEB.getPermission())) {
consoleRegister(args, sender, notEnoughArgsMsg); if (CommandUtils.isPlayer(sender)) {
String playerName = sender.getName();
UUID linkedToUUID = uuidUtility.getUUIDOf(playerName);
String username = arguments.get(1).orElse(playerName);
registerUser(new User(username, playerName, linkedToUUID, passwordHash, Collections.emptyList()), sender, permissionLevel);
} else { } else {
sender.sendMessage(locale.getString(CommandLang.FAIL_NO_PERMISSION)); String username = arguments.get(1)
.orElseThrow(() -> new IllegalArgumentException(notEnoughArgsMsg));
registerUser(new User(username, "console", null, passwordHash, Collections.emptyList()), sender, permissionLevel);
} }
} }
@ -194,22 +185,22 @@ public class RegisterCommand extends CommandNode {
return 100; return 100;
} }
private void registerUser(WebUser webUser, Sender sender) { private void registerUser(User user, Sender sender, int permissionLevel) {
processing.submitCritical(() -> { processing.submitCritical(() -> {
String userName = webUser.getName(); String username = user.getUsername();
try { try {
Database database = dbSystem.getDatabase(); Database database = dbSystem.getDatabase();
boolean userExists = database.query(WebUserQueries.fetchWebUser(userName)).isPresent(); boolean userExists = database.query(WebUserQueries.fetchUser(username)).isPresent();
if (userExists) { if (userExists) {
sender.sendMessage(locale.getString(CommandLang.FAIL_WEB_USER_EXISTS)); sender.sendMessage(locale.getString(CommandLang.FAIL_WEB_USER_EXISTS));
return; return;
} }
database.executeTransaction(new RegisterWebUserTransaction(webUser)) database.executeTransaction(new RegisterWebUserTransaction(user, permissionLevel))
.get(); // Wait for completion .get(); // Wait for completion
sender.sendMessage(locale.getString(CommandLang.WEB_USER_REGISTER_SUCCESS, userName)); sender.sendMessage(locale.getString(CommandLang.WEB_USER_REGISTER_SUCCESS, username));
sendLink(sender); sendLink(sender);
logger.info(locale.getString(CommandLang.WEB_USER_REGISTER_NOTIFY, userName, webUser.getPermLevel())); logger.info(locale.getString(CommandLang.WEB_USER_REGISTER_NOTIFY, username, permissionLevel));
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch (DBOpException | ExecutionException e) { } catch (DBOpException | ExecutionException e) {

View File

@ -30,18 +30,32 @@ import java.util.Objects;
@Deprecated @Deprecated
public class WebUser { public class WebUser {
private final String user; private final String username;
private final String saltedPassHash; private final String saltedPassHash;
private final int permLevel; private final int permLevel;
public WebUser(String user, String saltedPassHash, int permLevel) { public WebUser(String username, String saltedPassHash, int permLevel) {
this.user = user; this.username = username;
this.saltedPassHash = saltedPassHash; this.saltedPassHash = saltedPassHash;
this.permLevel = permLevel; this.permLevel = permLevel;
} }
public String getName() { public static List<String> getPermissionsForLevel(int level) {
return user; List<String> permissions = new ArrayList<>();
if (level <= 0) {
permissions.add("page.network");
permissions.add("page.server");
permissions.add("page.debug");
// TODO Add JSON Permissions
}
if (level <= 1) {
permissions.add("page.players");
permissions.add("page.player.other");
}
if (level <= 2) {
permissions.add("page.player.self");
}
return permissions;
} }
public String getSaltedPassHash() { public String getSaltedPassHash() {
@ -52,38 +66,28 @@ public class WebUser {
return permLevel; return permLevel;
} }
public String getName() {
return username;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
WebUser webUser = (WebUser) o; WebUser webUser = (WebUser) o;
return permLevel == webUser.permLevel && return permLevel == webUser.permLevel &&
Objects.equals(user, webUser.user) && Objects.equals(username, webUser.username) &&
Objects.equals(saltedPassHash, webUser.saltedPassHash); Objects.equals(saltedPassHash, webUser.saltedPassHash);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(user, saltedPassHash, permLevel); return Objects.hash(username, saltedPassHash, permLevel);
} }
public com.djrapitops.plan.delivery.web.resolver.request.WebUser toNewWebUser() { public com.djrapitops.plan.delivery.web.resolver.request.WebUser toNewWebUser() {
List<String> permissions = new ArrayList<>();
if (permLevel <= 0) {
permissions.add("page.network");
permissions.add("page.server");
permissions.add("page.debug");
// TODO Add JSON Permissions
}
if (permLevel <= 1) {
permissions.add("page.players");
permissions.add("page.player.other");
}
if (permLevel <= 2) {
permissions.add("page.player.self");
}
return new com.djrapitops.plan.delivery.web.resolver.request.WebUser( return new com.djrapitops.plan.delivery.web.resolver.request.WebUser(
user, permissions.toArray(new String[0]) username, getPermissionsForLevel(permLevel).toArray(new String[0])
); );
} }
} }

View File

@ -0,0 +1,69 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.delivery.domain.auth;
import com.djrapitops.plan.delivery.web.resolver.request.WebUser;
import com.djrapitops.plan.utilities.PassEncryptUtil;
import java.util.Collection;
import java.util.UUID;
/**
* Represents a registered user in the database.
*
* @author Rsl1122
*/
public class User {
private final String username;
private final String linkedTo;
private final UUID linkedToUUID; // null for 'console'
private final String passwordHash;
private final Collection<String> permissions;
public User(String username, String linkedTo, UUID linkedToUUID, String passwordHash, Collection<String> permissions) {
this.username = username;
this.linkedTo = linkedTo;
this.linkedToUUID = linkedToUUID;
this.passwordHash = passwordHash;
this.permissions = permissions;
}
public boolean doesPasswordMatch(String password) {
return PassEncryptUtil.verifyPassword(password, passwordHash);
}
public WebUser toWebUser() {
return new WebUser(linkedTo, username, permissions);
}
public String getUsername() {
return username;
}
public String getLinkedTo() {
return linkedTo;
}
public UUID getLinkedToUUID() {
return linkedToUUID;
}
public String getPasswordHash() {
return passwordHash;
}
}

View File

@ -16,6 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver; package com.djrapitops.plan.delivery.webserver;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.delivery.web.resolver.Response; import com.djrapitops.plan.delivery.web.resolver.Response;
import com.djrapitops.plan.delivery.web.resolver.request.Request; import com.djrapitops.plan.delivery.web.resolver.request.Request;
import com.djrapitops.plan.delivery.web.resolver.request.URIPath; import com.djrapitops.plan.delivery.web.resolver.request.URIPath;
@ -153,8 +154,8 @@ public class RequestHandler implements HttpHandler {
private WebUser getWebUser(HttpExchange exchange) { private WebUser getWebUser(HttpExchange exchange) {
return getAuthentication(exchange.getRequestHeaders()) return getAuthentication(exchange.getRequestHeaders())
.map(Authentication::getWebUser) // Can throw WebUserAuthException .map(Authentication::getUser) // Can throw WebUserAuthException
.map(com.djrapitops.plan.delivery.domain.WebUser::toNewWebUser) .map(User::toWebUser)
.orElse(null); .orElse(null);
} }

View File

@ -16,7 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver.auth; package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import java.util.HashMap; import java.util.HashMap;
@ -26,14 +26,14 @@ import java.util.UUID;
public class ActiveCookieStore { public class ActiveCookieStore {
private static final Map<String, WebUser> USERS_BY_COOKIE = new HashMap<>(); private static final Map<String, User> USERS_BY_COOKIE = new HashMap<>();
public static Optional<WebUser> checkCookie(String cookie) { public static Optional<User> checkCookie(String cookie) {
return Optional.ofNullable(USERS_BY_COOKIE.get(cookie)); return Optional.ofNullable(USERS_BY_COOKIE.get(cookie));
} }
public static String generateNewCookie(WebUser user) { public static String generateNewCookie(User user) {
String cookie = DigestUtils.sha256Hex(user.getName() + UUID.randomUUID() + System.currentTimeMillis()); String cookie = DigestUtils.sha256Hex(user.getUsername() + UUID.randomUUID() + System.currentTimeMillis());
USERS_BY_COOKIE.put(cookie, user); USERS_BY_COOKIE.put(cookie, user);
return cookie; return cookie;
} }
@ -42,8 +42,8 @@ public class ActiveCookieStore {
USERS_BY_COOKIE.remove(cookie); USERS_BY_COOKIE.remove(cookie);
} }
public static void removeCookie(WebUser user) { public static void removeCookie(User user) {
USERS_BY_COOKIE.entrySet().stream().filter(entry -> entry.getValue().getName().equals(user.getName())) USERS_BY_COOKIE.entrySet().stream().filter(entry -> entry.getValue().getUsername().equals(user.getUsername()))
.findAny() .findAny()
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.ifPresent(ActiveCookieStore::removeCookie); .ifPresent(ActiveCookieStore::removeCookie);

View File

@ -16,7 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver.auth; package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.exceptions.WebUserAuthException; import com.djrapitops.plan.exceptions.WebUserAuthException;
/** /**
@ -32,6 +32,6 @@ public interface Authentication {
* @return Web user for the authentication. * @return Web user for the authentication.
* @throws WebUserAuthException If user can't be authenticated * @throws WebUserAuthException If user can't be authenticated
*/ */
WebUser getWebUser(); User getUser();
} }

View File

@ -16,14 +16,13 @@
*/ */
package com.djrapitops.plan.delivery.webserver.auth; package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.exceptions.PassEncryptException; import com.djrapitops.plan.exceptions.PassEncryptException;
import com.djrapitops.plan.exceptions.WebUserAuthException; import com.djrapitops.plan.exceptions.WebUserAuthException;
import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.Database;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.utilities.Base64Util; import com.djrapitops.plan.utilities.Base64Util;
import com.djrapitops.plan.utilities.PassEncryptUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import java.util.Arrays;
@ -47,7 +46,7 @@ public class BasicAuthentication implements Authentication {
} }
@Override @Override
public WebUser getWebUser() { public User getUser() {
String decoded = Base64Util.decode(authenticationString); String decoded = Base64Util.decode(authenticationString);
String[] userInfo = StringUtils.split(decoded, ':'); String[] userInfo = StringUtils.split(decoded, ':');
@ -55,7 +54,7 @@ public class BasicAuthentication implements Authentication {
throw new WebUserAuthException(FailReason.USER_AND_PASS_NOT_SPECIFIED, Arrays.toString(userInfo)); throw new WebUserAuthException(FailReason.USER_AND_PASS_NOT_SPECIFIED, Arrays.toString(userInfo));
} }
String user = userInfo[0]; String username = userInfo[0];
String passwordRaw = userInfo[1]; String passwordRaw = userInfo[1];
Database.State dbState = database.getState(); Database.State dbState = database.getState();
@ -64,14 +63,14 @@ public class BasicAuthentication implements Authentication {
} }
try { try {
WebUser webUser = database.query(WebUserQueries.fetchWebUser(user)) User user = database.query(WebUserQueries.fetchUser(username))
.orElseThrow(() -> new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, user)); .orElseThrow(() -> new WebUserAuthException(FailReason.USER_DOES_NOT_EXIST, username));
boolean correctPass = PassEncryptUtil.verifyPassword(passwordRaw, webUser.getSaltedPassHash()); boolean correctPass = user.doesPasswordMatch(passwordRaw);
if (!correctPass) { if (!correctPass) {
throw new WebUserAuthException(FailReason.USER_PASS_MISMATCH, user); throw new WebUserAuthException(FailReason.USER_PASS_MISMATCH, username);
} }
return webUser; return user;
} catch (DBOpException | PassEncryptException e) { } catch (DBOpException | PassEncryptException e) {
throw new WebUserAuthException(e); throw new WebUserAuthException(e);
} }

View File

@ -16,7 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver.auth; package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
public class CookieAuthentication implements Authentication { public class CookieAuthentication implements Authentication {
@ -27,7 +27,7 @@ public class CookieAuthentication implements Authentication {
} }
@Override @Override
public WebUser getWebUser() { public User getUser() {
return ActiveCookieStore.checkCookie(cookie).orElse(null); return ActiveCookieStore.checkCookie(cookie).orElse(null);
} }
} }

View File

@ -16,13 +16,11 @@
*/ */
package com.djrapitops.plan.delivery.webserver.auth; package com.djrapitops.plan.delivery.webserver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.utilities.PassEncryptUtil; import com.djrapitops.plan.utilities.PassEncryptUtil;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.Optional;
/** /**
* Holds registrations of users before they are confirmed. * Holds registrations of users before they are confirmed.
@ -33,18 +31,18 @@ public class RegistrationBin {
private static final Map<String, AwaitingForRegistration> REGISTRATION_BIN = new HashMap<>(); private static final Map<String, AwaitingForRegistration> REGISTRATION_BIN = new HashMap<>();
public static String addInfoForRegistration(String username, String password) throws PassEncryptUtil.CannotPerformOperationException { public static String addInfoForRegistration(String username, String password) {
String hash = PassEncryptUtil.createHash(password); String hash = PassEncryptUtil.createHash(password);
String code = DigestUtils.sha256Hex(username + password + System.currentTimeMillis()).substring(0, 12); String code = DigestUtils.sha256Hex(username + password + System.currentTimeMillis()).substring(0, 12);
REGISTRATION_BIN.put(code, new AwaitingForRegistration(username, hash)); REGISTRATION_BIN.put(code, new AwaitingForRegistration(username, hash));
return code; return code;
} }
public static Optional<WebUser> register(String code, int permissionLevel) { public static Optional<User> register(String code, UUID linkedToUUID) {
AwaitingForRegistration found = REGISTRATION_BIN.get(code); AwaitingForRegistration found = REGISTRATION_BIN.get(code);
if (found == null) return Optional.empty(); if (found == null) return Optional.empty();
REGISTRATION_BIN.remove(code); REGISTRATION_BIN.remove(code);
return Optional.of(found.toWebUser(permissionLevel)); return Optional.of(found.toUser(linkedToUUID));
} }
public static boolean contains(String code) { public static boolean contains(String code) {
@ -60,8 +58,8 @@ public class RegistrationBin {
this.passwordHash = passwordHash; this.passwordHash = passwordHash;
} }
public WebUser toWebUser(int permissionLevel) { public User toUser(UUID linkedToUUID) {
return new WebUser(username, passwordHash, permissionLevel); return new User(username, null, linkedToUUID, passwordHash, Collections.emptyList());
} }
} }
} }

View File

@ -16,7 +16,7 @@
*/ */
package com.djrapitops.plan.delivery.webserver.resolver.auth; package com.djrapitops.plan.delivery.webserver.resolver.auth;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.delivery.web.resolver.NoAuthResolver; import com.djrapitops.plan.delivery.web.resolver.NoAuthResolver;
import com.djrapitops.plan.delivery.web.resolver.Response; import com.djrapitops.plan.delivery.web.resolver.Response;
import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException; import com.djrapitops.plan.delivery.web.resolver.exception.BadRequestException;
@ -29,7 +29,6 @@ import com.djrapitops.plan.exceptions.WebUserAuthException;
import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.DBSystem;
import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries; import com.djrapitops.plan.storage.database.queries.objects.WebUserQueries;
import com.djrapitops.plan.utilities.PassEncryptUtil;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -52,7 +51,7 @@ public class LoginResolver implements NoAuthResolver {
@Override @Override
public Optional<Response> resolve(Request request) { public Optional<Response> resolve(Request request) {
try { try {
String cookie = ActiveCookieStore.generateNewCookie(getWebUser(request)); String cookie = ActiveCookieStore.generateNewCookie(getUser(request));
return Optional.of(getResponse(cookie)); return Optional.of(getResponse(cookie));
} catch (DBOpException | PassEncryptException e) { } catch (DBOpException | PassEncryptException e) {
throw new WebUserAuthException(e); throw new WebUserAuthException(e);
@ -67,17 +66,17 @@ public class LoginResolver implements NoAuthResolver {
.build(); .build();
} }
public WebUser getWebUser(Request request) throws PassEncryptUtil.CannotPerformOperationException, PassEncryptUtil.InvalidHashException { public User getUser(Request request) {
URIQuery query = request.getQuery(); URIQuery query = request.getQuery();
String username = query.get("user").orElseThrow(() -> new BadRequestException("'user' parameter not defined")); String username = query.get("user").orElseThrow(() -> new BadRequestException("'user' parameter not defined"));
String password = query.get("password").orElseThrow(() -> new BadRequestException("'password' parameter not defined")); String password = query.get("password").orElseThrow(() -> new BadRequestException("'password' parameter not defined"));
WebUser webUser = dbSystem.getDatabase().query(WebUserQueries.fetchWebUser(username)) User user = dbSystem.getDatabase().query(WebUserQueries.fetchUser(username))
.orElseThrow(() -> new BadRequestException(FailReason.USER_DOES_NOT_EXIST.getReason() + ": " + username)); .orElseThrow(() -> new BadRequestException(FailReason.USER_DOES_NOT_EXIST.getReason() + ": " + username));
boolean correctPass = PassEncryptUtil.verifyPassword(password, webUser.getSaltedPassHash()); boolean correctPass = user.doesPasswordMatch(password);
if (!correctPass) { if (!correctPass) {
throw new WebUserAuthException(FailReason.USER_PASS_MISMATCH); throw new WebUserAuthException(FailReason.USER_PASS_MISMATCH);
} }
return webUser; return user;
} }
} }

View File

@ -57,7 +57,7 @@ public class RegisterResolver implements NoAuthResolver {
String username = query.get("user").orElseThrow(() -> new BadRequestException("'user' parameter not defined")); String username = query.get("user").orElseThrow(() -> new BadRequestException("'user' parameter not defined"));
boolean alreadyExists = dbSystem.getDatabase().query(WebUserQueries.fetchWebUser(username)).isPresent(); boolean alreadyExists = dbSystem.getDatabase().query(WebUserQueries.fetchUser(username)).isPresent();
if (alreadyExists) throw new BadRequestException("User '" + username + "' already exists!"); if (alreadyExists) throw new BadRequestException("User '" + username + "' already exists!");
String password = query.get("password").orElseThrow(() -> new BadRequestException("'password' parameter not defined")); String password = query.get("password").orElseThrow(() -> new BadRequestException("'password' parameter not defined"));

View File

@ -16,7 +16,7 @@
*/ */
package com.djrapitops.plan.exceptions; package com.djrapitops.plan.exceptions;
public class PassEncryptException extends Exception { public class PassEncryptException extends IllegalArgumentException {
public PassEncryptException(String s) { public PassEncryptException(String s) {
super(s); super(s);

View File

@ -170,7 +170,9 @@ public abstract class SQLDB extends AbstractDatabase {
new ExtensionTableRowValueLengthPatch(), new ExtensionTableRowValueLengthPatch(),
new CommandUsageTableRemovalPatch(), new CommandUsageTableRemovalPatch(),
new RegisterDateMinimizationPatch(), new RegisterDateMinimizationPatch(),
new BadNukkitRegisterValuePatch() new BadNukkitRegisterValuePatch(),
new LinkedToSecurityTablePatch(),
new LinkUsersToPlayersSecurityTablePatch()
}; };
} }

View File

@ -17,10 +17,12 @@
package com.djrapitops.plan.storage.database.queries.objects; package com.djrapitops.plan.storage.database.queries.objects;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.WebUser;
import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.storage.database.queries.Query; import com.djrapitops.plan.storage.database.queries.Query;
import com.djrapitops.plan.storage.database.queries.QueryAllStatement; import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
import com.djrapitops.plan.storage.database.queries.QueryStatement; import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable; import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
@ -28,11 +30,12 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import static com.djrapitops.plan.storage.database.sql.building.Sql.*; import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
/** /**
* Queries for {@link WebUser} objects. * Queries for web user objects.
* *
* @author Rsl1122 * @author Rsl1122
*/ */
@ -47,6 +50,7 @@ public class WebUserQueries {
* *
* @return List of Plan WebUsers. * @return List of Plan WebUsers.
*/ */
@Deprecated
public static Query<List<WebUser>> fetchAllPlanWebUsers() { public static Query<List<WebUser>> fetchAllPlanWebUsers() {
String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME + ORDER_BY + SecurityTable.PERMISSION_LEVEL + " ASC"; String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME + ORDER_BY + SecurityTable.PERMISSION_LEVEL + " ASC";
@ -66,6 +70,31 @@ public class WebUserQueries {
}; };
} }
public static Query<Optional<User>> fetchUser(String username) {
String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME +
LEFT_JOIN + UsersTable.TABLE_NAME + " on " + SecurityTable.LINKED_TO + "=" + UsersTable.USER_UUID +
WHERE + SecurityTable.USERNAME + "=? LIMIT 1";
return new QueryStatement<Optional<User>>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, username);
}
@Override
public Optional<User> processResults(ResultSet set) throws SQLException {
if (set.next()) {
String linkedTo = set.getString(UsersTable.USER_NAME);
UUID linkedToUUID = linkedTo != null ? UUID.fromString(set.getString(SecurityTable.LINKED_TO)) : null;
String passwordHash = set.getString(SecurityTable.SALT_PASSWORD_HASH);
List<String> permissions = WebUser.getPermissionsForLevel(set.getInt(SecurityTable.PERMISSION_LEVEL));
return Optional.of(new User(username, linkedTo != null ? linkedTo : "console", linkedToUUID, passwordHash, permissions));
}
return Optional.empty();
}
};
}
@Deprecated
public static Query<Optional<WebUser>> fetchWebUser(String called) { public static Query<Optional<WebUser>> fetchWebUser(String called) {
String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME + String sql = SELECT + '*' + FROM + SecurityTable.TABLE_NAME +
WHERE + SecurityTable.USERNAME + "=? LIMIT 1"; WHERE + SecurityTable.USERNAME + "=? LIMIT 1";

View File

@ -18,7 +18,6 @@ package com.djrapitops.plan.storage.database.sql.tables;
import com.djrapitops.plan.storage.database.DBType; import com.djrapitops.plan.storage.database.DBType;
import com.djrapitops.plan.storage.database.sql.building.CreateTableBuilder; import com.djrapitops.plan.storage.database.sql.building.CreateTableBuilder;
import com.djrapitops.plan.storage.database.sql.building.Insert;
import com.djrapitops.plan.storage.database.sql.building.Sql; import com.djrapitops.plan.storage.database.sql.building.Sql;
/** /**
@ -31,10 +30,15 @@ public class SecurityTable {
public static final String TABLE_NAME = "plan_security"; public static final String TABLE_NAME = "plan_security";
public static final String USERNAME = "username"; public static final String USERNAME = "username";
public static final String LINKED_TO = "linked_to_uuid";
public static final String SALT_PASSWORD_HASH = "salted_pass_hash"; public static final String SALT_PASSWORD_HASH = "salted_pass_hash";
public static final String PERMISSION_LEVEL = "permission_level"; public static final String PERMISSION_LEVEL = "permission_level";
public static final String INSERT_STATEMENT = Insert.values(TABLE_NAME, USERNAME, SALT_PASSWORD_HASH, PERMISSION_LEVEL); public static final String INSERT_STATEMENT = "INSERT INTO " + TABLE_NAME + " (" +
USERNAME + ',' +
LINKED_TO + ',' +
SALT_PASSWORD_HASH + ',' +
PERMISSION_LEVEL + ") VALUES (?,?,?,?)";
private SecurityTable() { private SecurityTable() {
/* Static information class */ /* Static information class */
@ -43,6 +47,7 @@ public class SecurityTable {
public static String createTableSQL(DBType dbType) { public static String createTableSQL(DBType dbType) {
return CreateTableBuilder.create(TABLE_NAME, dbType) return CreateTableBuilder.create(TABLE_NAME, dbType)
.column(USERNAME, Sql.varchar(100)).notNull().unique() .column(USERNAME, Sql.varchar(100)).notNull().unique()
.column(LINKED_TO, Sql.varchar(36))
.column(SALT_PASSWORD_HASH, Sql.varchar(100)).notNull().unique() .column(SALT_PASSWORD_HASH, Sql.varchar(100)).notNull().unique()
.column(PERMISSION_LEVEL, Sql.INT).notNull() .column(PERMISSION_LEVEL, Sql.INT).notNull()
.toString(); .toString();

View File

@ -16,25 +16,28 @@
*/ */
package com.djrapitops.plan.storage.database.transactions.commands; package com.djrapitops.plan.storage.database.transactions.commands;
import com.djrapitops.plan.delivery.domain.WebUser; import com.djrapitops.plan.delivery.domain.auth.User;
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable; import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
import com.djrapitops.plan.storage.database.transactions.ExecStatement; import com.djrapitops.plan.storage.database.transactions.ExecStatement;
import com.djrapitops.plan.storage.database.transactions.Transaction; import com.djrapitops.plan.storage.database.transactions.Transaction;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types;
/** /**
* Transaction to save a new Plan {@link WebUser} to the database. * Transaction to save a new Plan {@link User} to the database.
* *
* @author Rsl1122 * @author Rsl1122
*/ */
public class RegisterWebUserTransaction extends Transaction { public class RegisterWebUserTransaction extends Transaction {
private final WebUser webUser; private final User user;
private final int permissionLevel;
public RegisterWebUserTransaction(WebUser webUser) { public RegisterWebUserTransaction(User user, int permissionLevel) {
this.webUser = webUser; this.user = user;
this.permissionLevel = permissionLevel;
} }
@Override @Override
@ -42,9 +45,14 @@ public class RegisterWebUserTransaction extends Transaction {
execute(new ExecStatement(SecurityTable.INSERT_STATEMENT) { execute(new ExecStatement(SecurityTable.INSERT_STATEMENT) {
@Override @Override
public void prepare(PreparedStatement statement) throws SQLException { public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, webUser.getName()); statement.setString(1, user.getUsername());
statement.setString(2, webUser.getSaltedPassHash()); if (user.getLinkedToUUID() == null) {
statement.setInt(3, webUser.getPermLevel()); statement.setNull(2, Types.VARCHAR);
} else {
statement.setString(2, user.getLinkedToUUID().toString());
}
statement.setString(3, user.getPasswordHash());
statement.setInt(4, permissionLevel);
} }
}); });
} }

View File

@ -0,0 +1,78 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database.transactions.patches;
import com.djrapitops.plan.storage.database.queries.HasMoreThanZeroQueryStatement;
import com.djrapitops.plan.storage.database.queries.QueryAllStatement;
import com.djrapitops.plan.storage.database.sql.building.Sql;
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
import com.djrapitops.plan.storage.database.sql.tables.UsersTable;
import com.djrapitops.plan.storage.database.transactions.ExecBatchStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import static com.djrapitops.plan.storage.database.sql.building.Sql.*;
public class LinkUsersToPlayersSecurityTablePatch extends Patch {
@Override
public boolean hasBeenApplied() {
String sql = SELECT + "COUNT(1) as c" + FROM + SecurityTable.TABLE_NAME +
WHERE + SecurityTable.LINKED_TO + "=''";
return !query(new HasMoreThanZeroQueryStatement(sql) {
@Override
public void prepare(PreparedStatement statement) {
// No preparation necessary
}
});
}
@Override
protected void applyPatch() {
String querySQL = SELECT + UsersTable.USER_UUID + ',' + SecurityTable.USERNAME +
FROM + SecurityTable.TABLE_NAME +
LEFT_JOIN + UsersTable.TABLE_NAME + " on " + UsersTable.USER_NAME + "=" + SecurityTable.USERNAME +
WHERE + SecurityTable.LINKED_TO + "=''";
String sql = "UPDATE " + SecurityTable.TABLE_NAME + " SET " + SecurityTable.LINKED_TO + "=?" +
WHERE + SecurityTable.USERNAME + "=?";
Map<String, String> byUsername = query(new QueryAllStatement<Map<String, String>>(querySQL) {
@Override
public Map<String, String> processResults(ResultSet set) throws SQLException {
Map<String, String> byUsername = new HashMap<>();
while (set.next()) {
byUsername.put(set.getString(SecurityTable.USERNAME), set.getString(UsersTable.USER_UUID));
}
return byUsername;
}
});
execute(new ExecBatchStatement(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
for (Map.Entry<String, String> usernameUUIDPair : byUsername.entrySet()) {
Sql.setStringOrNull(statement, 1, usernameUUIDPair.getValue());
statement.setString(2, usernameUUIDPair.getKey());
statement.addBatch();
}
}
});
}
}

View File

@ -0,0 +1,33 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.storage.database.transactions.patches;
import com.djrapitops.plan.storage.database.sql.building.Sql;
import com.djrapitops.plan.storage.database.sql.tables.SecurityTable;
public class LinkedToSecurityTablePatch extends Patch {
@Override
public boolean hasBeenApplied() {
return hasColumn(SecurityTable.TABLE_NAME, SecurityTable.LINKED_TO);
}
@Override
protected void applyPatch() {
addColumn(SecurityTable.TABLE_NAME, SecurityTable.LINKED_TO + ' ' + Sql.varchar(36) + " DEFAULT ''");
}
}

View File

@ -55,11 +55,18 @@ public class PassEncryptUtil {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
public static String createHash(String password) throws CannotPerformOperationException { /**
* Create a hash of password + salt.
*
* @param password Password
* @return Hash + salt
* @throws CannotPerformOperationException If the hash creation fails
*/
public static String createHash(String password) {
return createHash(password.toCharArray()); return createHash(password.toCharArray());
} }
private static String createHash(char[] password) throws CannotPerformOperationException { private static String createHash(char[] password) {
// Generate a random salt // Generate a random salt
SecureRandom random = new SecureRandom(); SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_BYTE_SIZE]; byte[] salt = new byte[SALT_BYTE_SIZE];
@ -77,11 +84,20 @@ public class PassEncryptUtil {
+ ":" + toBase64(hash); + ":" + toBase64(hash);
} }
public static boolean verifyPassword(String password, String correctHash) throws CannotPerformOperationException, InvalidHashException { /**
* Verify that a password matches a hash.
*
* @param password Password
* @param correctHash hash created with {@link PassEncryptUtil#createHash(String)}
* @return true if match
* @throws CannotPerformOperationException If hashing fails
* @throws InvalidHashException If the hash is missing details.
*/
public static boolean verifyPassword(String password, String correctHash) {
return verifyPassword(password.toCharArray(), correctHash); return verifyPassword(password.toCharArray(), correctHash);
} }
private static boolean verifyPassword(char[] password, String correctHash) throws CannotPerformOperationException, InvalidHashException { private static boolean verifyPassword(char[] password, String correctHash) {
// Decode the hash into its parameters // Decode the hash into its parameters
String[] params = StringUtils.split(correctHash, ':'); String[] params = StringUtils.split(correctHash, ':');
if (params.length != HASH_SECTIONS) { if (params.length != HASH_SECTIONS) {
@ -160,7 +176,7 @@ public class PassEncryptUtil {
return diff == 0; return diff == 0;
} }
private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) throws CannotPerformOperationException { private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) {
try { try {
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8); PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM); SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);

View File

@ -59,7 +59,7 @@ class JksHttpsServerTest implements HttpsServerTest {
system.enable(); system.enable();
WebUser webUser = new WebUser("test", PassEncryptUtil.createHash("testPass"), 0); WebUser webUser = new WebUser("test", PassEncryptUtil.createHash("testPass"), 0);
system.getDatabaseSystem().getDatabase().executeTransaction(new RegisterWebUserTransaction(webUser)); system.getDatabaseSystem().getDatabase().executeTransaction(new RegisterWebUserTransaction(webUser, ));
} }
@AfterAll @AfterAll

View File

@ -64,7 +64,7 @@ class Pkcs12HttpsServerTest implements HttpsServerTest {
system.enable(); system.enable();
WebUser webUser = new WebUser("test", PassEncryptUtil.createHash("testPass"), 0); WebUser webUser = new WebUser("test", PassEncryptUtil.createHash("testPass"), 0);
system.getDatabaseSystem().getDatabase().executeTransaction(new RegisterWebUserTransaction(webUser)); system.getDatabaseSystem().getDatabase().executeTransaction(new RegisterWebUserTransaction(webUser, ));
} }
@AfterAll @AfterAll

View File

@ -68,7 +68,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer {
); );
WebUser webUser = new WebUser(TestConstants.PLAYER_ONE_NAME, RandomData.randomString(100), 0); WebUser webUser = new WebUser(TestConstants.PLAYER_ONE_NAME, RandomData.randomString(100), 0);
db().executeTransaction(new RegisterWebUserTransaction(webUser)); db().executeTransaction(new RegisterWebUserTransaction(webUser, ));
} }
@Test @Test

View File

@ -34,7 +34,7 @@ public interface WebUserQueriesTest extends DatabaseTestPreparer {
@Test @Test
default void webUserIsRegistered() { default void webUserIsRegistered() {
WebUser expected = new WebUser(TestConstants.PLAYER_ONE_NAME, "RandomGarbageBlah", 0); WebUser expected = new WebUser(TestConstants.PLAYER_ONE_NAME, "RandomGarbageBlah", 0);
db().executeTransaction(new RegisterWebUserTransaction(expected)); db().executeTransaction(new RegisterWebUserTransaction(expected, ));
forcePersistenceCheck(); forcePersistenceCheck();
Optional<WebUser> found = db().query(WebUserQueries.fetchWebUser(TestConstants.PLAYER_ONE_NAME)); Optional<WebUser> found = db().query(WebUserQueries.fetchWebUser(TestConstants.PLAYER_ONE_NAME));