package dbProcs;
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import utils.CountdownHandler;
import utils.InvalidCountdownStateException;
/**
* Used to add information to the Database
*
* This file is part of the Security Shepherd Project.
*
*
The Security Shepherd project is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
*
The Security Shepherd project 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 General Public License for more details.
*
*
You should have received a copy of the GNU General Public License along with the Security
* Shepherd project. If not, see .
*
* @author Mark
*/
public class Setter {
private static final Logger log = LogManager.getLogger(Setter.class);
// TODO - Replace this with a new mobile/web/etc attribute in the modules table
public static final String webModuleCategoryHardcodedWhereClause =
new String(
"moduleCategory = 'CSRF'"
+ " OR moduleCategory = 'Failure to Restrict URL Access'"
+ " OR moduleCategory = 'Injection'"
+ " OR moduleCategory = 'Insecure Cryptographic Storage'"
+ " OR moduleCategory = 'Insecure Direct Object References'"
+ " OR moduleCategory = 'Poor Data Validation'"
+ " OR moduleCategory = 'Security Misconfigurations'"
+ " OR moduleCategory = 'Session Management'"
+ " OR moduleCategory = 'Unvalidated Redirects and Forwards'"
+ " OR moduleCategory = 'XSS'");
public static final String mobileModuleCategoryHardcodedWhereClause =
new String(
""
+ "moduleCategory = 'Mobile Broken Crypto'"
+ " OR moduleCategory = 'Mobile Content Provider'"
+ " OR moduleCategory = 'Mobile Data Leakage'"
+ " OR moduleCategory = 'Mobile Injection'"
+ " OR moduleCategory = 'Mobile Insecure Data Storage'"
+ " OR moduleCategory = 'Mobile Poor Authentication'"
+ " OR moduleCategory = 'Mobile Reverse Engineering'"
+ " OR moduleCategory = 'Mobile Security Decisions via Untrusted Input'");
/**
* Database procedure just adds this. So this method just prepares the statement
*
* @param ApplicationRoot
* @param className Class name
* @param classYear Year of the class in YY/YY. eg 11/12
* @return
*/
public static boolean classCreate(String ApplicationRoot, String className, String classYear) {
log.debug("*** Setter.classCreate ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing classCreate call");
CallableStatement callstmnt = conn.prepareCall("call classCreate(?, ?)");
callstmnt.setString(1, className);
callstmnt.setString(2, classYear);
log.debug("Executing classCreate");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("classCreate Failure: " + e.toString());
}
log.debug("*** END classCreate ***");
return result;
}
/**
* This method sets every module status to Closed.
*
* @param ApplicationRoot Current running director of the application
* @return Boolean result depicting success of statement
*/
public static boolean closeAllModules(String ApplicationRoot) {
log.debug("*** Setter.closeAllModules ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
PreparedStatement callstmt =
conn.prepareStatement("UPDATE modules SET moduleStatus = 'closed'");
callstmt.execute();
log.debug("All modules Set to closed");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not close all modules: " + e.toString());
}
log.debug("*** END closeAllModules ***");
return result;
}
/**
* Used to increment bad submission counter in DB. DB will handle point deductions once the
* counter hits 40
*
* @param ApplicationRoot application running context
* @param userId user identifier to increment
* @return False if the statement fails to execute
*/
public static boolean incrementBadSubmission(String ApplicationRoot, String userId) {
log.debug("*** Setter.incrementBadSubmission ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Prepairing bad Submission call");
PreparedStatement callstmnt = conn.prepareCall("CALL userBadSubmission(?)");
callstmnt.setString(1, userId);
log.debug("Executing userBadSubmission statement on id '" + userId + "'");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("userBadSubmission Failure: " + e.toString());
result = false;
}
log.debug("*** END userBadSubmisison ***");
return result;
}
/**
* This method sets every module status to Open.
*
* @param ApplicationRoot Current running director of the application
* @param unsafe set whether to open all safe modules or all modules that are unsafe
* @return Boolean result depicting success of statement
*/
public static boolean openAllModules(String ApplicationRoot, boolean unsafe) {
log.debug("*** Setter.openAllModules ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
if (unsafe) {
PreparedStatement callstmt =
conn.prepareStatement("UPDATE modules SET moduleStatus = 'open' WHERE isUnsafe = 1");
callstmt.execute();
log.debug("All unsafe modules set to open");
} else {
PreparedStatement callstmt =
conn.prepareStatement("UPDATE modules SET moduleStatus = 'open' WHERE isUnsafe = 0");
callstmt.execute();
log.debug("All safe modules set to open");
}
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not open all modules: " + e.toString());
}
log.debug("*** END setModuleStatusOpen ***");
return result;
}
/**
* This is used to only open Mobile category levels
*
* @param ApplicationRoot Used to locate database properties file
* @return
*/
public static boolean openOnlyMobileCategories(String ApplicationRoot) {
log.debug("*** Setter.openOnlyMobileCategories ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
PreparedStatement prepstmt =
conn.prepareStatement(
"UPDATE modules SET moduleStatus = 'closed' WHERE "
+ webModuleCategoryHardcodedWhereClause);
prepstmt.execute();
log.debug("Web Levels have been closed");
prepstmt =
conn.prepareStatement(
"UPDATE modules SET moduleStatus = 'open' WHERE "
+ mobileModuleCategoryHardcodedWhereClause);
prepstmt.execute();
log.debug("Mobile Levels have been opened");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not only open Mobile Levels: " + e.toString());
}
log.debug("*** END openOnlyMobileCategories ***");
return result;
}
/**
* This is used to only open Mobile category levels
*
* @param ApplicationRoot Used to locate database properties file
* @param unsafe Used to track if the level is deemed unsafe or safe
* @return
*/
public static boolean openOnlyWebCategories(String ApplicationRoot, int unsafe) {
log.debug("*** Setter.openOnlyWebCategories ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
PreparedStatement prepstmt =
conn.prepareStatement(
"UPDATE modules SET moduleStatus = 'open' WHERE "
+ "("
+ webModuleCategoryHardcodedWhereClause
+ ")"
+ " AND isUnsafe = "
+ unsafe);
prepstmt.execute();
log.debug("Web Levels have been opened");
prepstmt =
conn.prepareStatement(
"UPDATE modules SET moduleStatus = 'closed' WHERE "
+ mobileModuleCategoryHardcodedWhereClause);
prepstmt.execute();
log.debug("Mobile Levels have been closed");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not only open Web levels: " + e.toString());
}
log.debug("*** END openOnlyWebCategories ***");
return result;
}
/**
* Resets user bad submission counter to 0
*
* @param ApplicationRoot Application's running context
* @param userId User Identifier to reset
* @return
*/
public static boolean resetBadSubmission(String ApplicationRoot, String userId) {
log.debug("*** Setter.resetBadSubmission ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Prepairing resetUserBadSubmission call");
PreparedStatement callstmnt = conn.prepareCall("CALL resetUserBadSubmission(?)");
callstmnt.setString(1, userId);
log.debug("Executing resetUserBadSubmission statement on id '" + userId + "'");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("resetUserBadSubmission Failure: " + e.toString());
result = false;
}
log.debug("*** END resetBadSubmission ***");
return result;
}
/**
* This method converts the default database properties file at
* applicationRoot/WEB-INF/site.properties
*
* @param applicationRoot The directory that the server is actually in
* @param url The Url of the core Database
* @param userName The user name of the database user
* @param password The password of the database user
* @return Boolean value depicting the success of the method
*/
public static boolean setCoreDatabaseInfo(
String applicationRoot, String url, String userName, String password) {
userName = userName.toLowerCase();
try {
// Update Database Settings
File siteProperties = new File(applicationRoot + "/WEB-INF/database.properties");
DataOutputStream writer = new DataOutputStream(new FileOutputStream(siteProperties, false));
String theProperties =
new String("databaseConnectionURL=" + url + "\nDriverType=org.mariadb.jdbc.Driver");
writer.write(theProperties.getBytes());
writer.close();
// Update Core Schema Settings
siteProperties = new File(applicationRoot + "/WEB-INF/coreDatabase.properties");
writer = new DataOutputStream(new FileOutputStream(siteProperties, false));
theProperties =
new String(
"databaseConnectionURL=core"
+ "\ndatabaseUsername="
+ userName
+ "\ndatabasePassword="
+ password);
writer.write(theProperties.getBytes());
writer.close();
return true;
} catch (IOException e) {
log.error("Could not update Core Database Info: " + e.toString());
return false;
}
}
/**
* This method is used to store a CSRF Token for a specific user in the csrfChallengeSeven DB
* Schema. May not necessarily be a new CSRF token after running
*
* @param userId User Identifier
* @param csrfToken CSRF Token to add to the csrfChallengeFour DB Schema
* @param ApplicationRoot Running context of the application
* @return Returns current CSRF token for user for CSRF Ch4
*/
public static String setCsrfChallengeFourCsrfToken(
String userId, String csrfToken, String ApplicationRoot) {
log.debug("*** setCsrfChallengeFourToken ***");
try {
Connection conn = Database.getChallengeConnection(ApplicationRoot, "csrfChallengeFour");
boolean tokenExists = false;
log.debug("Preparing setSsrfChallengeFourToken call");
PreparedStatement callstmnt =
conn.prepareStatement("SELECT csrfTokenscol FROM csrfTokens WHERE userId = ?");
callstmnt.setString(1, userId);
log.debug("Executing setCsrfChallengeFourToken");
ResultSet rs = callstmnt.executeQuery();
if (rs.next()) {
// Need to Update CSRF token rather than Insert
log.debug("CSRF for Challenge 4 already is set");
csrfToken = rs.getString(1); // overwrite token with DB Stored Entry
tokenExists = true;
} else {
log.debug("No CSRF token Found for Challenge 4... Creating");
}
rs.close();
String whatToDo = new String();
if (!tokenExists) {
whatToDo =
"INSERT INTO `csrfChallengeFour`.`csrfTokens` (`csrfTokenscol`, `userId`) VALUES (?,"
+ " ?)";
}
callstmnt = conn.prepareStatement(whatToDo);
callstmnt.setString(1, csrfToken);
callstmnt.setString(2, userId);
callstmnt.execute();
callstmnt.close();
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("CsrfChallenge4 TokenUpdate Failure: " + e.toString());
}
return csrfToken;
}
/**
* This method is used to store a CSRF Token for a specific user in the csrfChallengeSix DB Schema
*
* @param userId User Identifier
* @param csrfToken CSRF Token to add to the csrfChallengeSix DB Schema
* @param ApplicationRoot Running context of the application
* @return
*/
public static boolean setCsrfChallengeSevenCsrfToken(
String userId, String csrfToken, String ApplicationRoot) {
log.debug("*** setCsrfChallengeSevenToken ***");
boolean result = false;
try {
Connection conn =
Database.getChallengeConnection(ApplicationRoot, "csrfChallengeEnumerateTokens");
boolean updateToken = false;
log.debug("Preparing setCsrfChallengeSevenToken call");
PreparedStatement prestmnt =
conn.prepareStatement("SELECT csrfTokenscol FROM csrfTokens WHERE userId = ?");
prestmnt.setString(1, userId);
log.debug("Executing setCsrfChallengeSevenToken");
ResultSet rs = prestmnt.executeQuery();
if (rs.next()) {
// Need to Update CSRF token rather than Insert
log.debug("CSRF token Found for Challenge 7... Updating");
updateToken = true;
} else {
log.debug("No CSRF token Found for Challenge 7... Creating");
}
rs.close();
String whatToDo;
if (updateToken) {
whatToDo =
"UPDATE `csrfChallengeEnumTokens`.`csrfTokens` SET csrfTokenscol = ? WHERE userId = ?";
} else {
whatToDo =
"INSERT INTO `csrfChallengeEnumTokens`.`csrfTokens` (`csrfTokenscol`, `userId`) VALUES"
+ " (?, ?)";
}
prestmnt = conn.prepareStatement(whatToDo);
prestmnt.setString(1, csrfToken);
prestmnt.setString(2, userId);
log.debug("Executing: " + whatToDo);
prestmnt.execute();
result = true;
prestmnt.close();
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("csrfChallenge7EnumTokens TokenUpdate Failure: " + e.toString());
}
return result;
}
/**
* This method is used to set the status of all modules in a category to open or closed.
*
* @param ApplicationRoot Used to locate database properties file
* @param moduleCategory The module category to open or closed
* @param openOrClosed What to set the module status to. Can only be "open" or "closed"
* @return True if method executes without failure
*/
public static boolean setModuleCategoryStatusOpen(
String ApplicationRoot, String moduleCategory, String openOrClosed) {
log.debug("*** Setter.setModuleCategoryStatusOpen ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
PreparedStatement prepstmt =
conn.prepareStatement("UPDATE modules SET moduleStatus = ? WHERE moduleCategory = ?");
prepstmt.setString(1, openOrClosed);
prepstmt.setString(2, moduleCategory);
prepstmt.execute();
log.debug("Set " + moduleCategory + " to " + openOrClosed);
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not open/close category: " + e.toString());
}
log.debug("*** END setModuleCategoryStatusOpen ***");
return result;
}
/**
* This method sets the module status to Closed. This information is absorbed by the Tournament
* Floor Plan
*
* @param ApplicationRoot Current running director of the application
* @param moduleId The identifier of the module that is been set to closed status
* @return Boolean result depicting success of statement
*/
public static boolean setModuleStatusClosed(String ApplicationRoot, String moduleId) {
log.debug("*** Setter.setModuleStatusClosed ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
CallableStatement callstmt = conn.prepareCall("call moduleSetStatus(?, ?)");
log.debug("Preparing moduleSetStatus procedure");
callstmt.setString(1, moduleId);
callstmt.setString(2, "closed");
callstmt.execute();
log.debug("Executed moduleSetStatus");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not execute moduleSetStatus: " + e.toString());
}
log.debug("*** END setModuleStatusClosed ***");
return result;
}
/**
* This method sets the module status to Open. This information is absorbed by the Tournament
* Floor Plan
*
* @param ApplicationRoot Current running director of the application
* @param moduleId The identifier of the module that is been set to open status
* @return Boolean result depicting success of statement
*/
public static boolean setModuleStatusOpen(String ApplicationRoot, String moduleId) {
log.debug("*** Setter.setModuleStatusOpen ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
CallableStatement callstmt = conn.prepareCall("call moduleSetStatus(?, ?)");
log.debug("Preparing moduleSetStatus procedure");
callstmt.setString(1, moduleId);
callstmt.setString(2, "open");
callstmt.execute();
log.debug("Executed moduleSetStatus");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not execute moduleSetStatus: " + e.toString());
}
log.debug("*** END setModuleStatusOpen ***");
return result;
}
/**
* Used by CSRF levels to store their CSRF attack string, that will be displayed in a CSRF forum
* for the class the user is in
*
* @param ApplicationRoot The current running context of the application
* @param message The String they want to store
* @param userId The identifier of the user in which to store the attack under
* @param moduleId The module identifier of which to store the message under
* @return A boolean value reflecting the success of the function
*/
public static boolean setStoredMessage(
String ApplicationRoot, String message, String userId, String moduleId) {
log.debug("*** Setter.setStoredMessage ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
CallableStatement callstmt = conn.prepareCall("call resultMessageSet(?, ?, ?)");
log.debug("Preparing resultMessageSet procedure");
callstmt.setString(1, message);
callstmt.setString(2, userId);
callstmt.setString(3, moduleId);
callstmt.execute();
log.debug("Executed resultMessageSet");
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not execute resultMessageSet: " + e.toString());
}
log.debug("*** END setStoredMessage ***");
return result;
}
/**
* Sets user to suspended in the database for a specific amount of time. This prevents them from
* signing into the application
*
* @param ApplicationRoot Running context of application
* @param userId User Identifier of the to be suspended user
* @param numberOfMinutes Amount of minutes to suspend user
* @return Returns true if statement succeeds without fatal error
*/
public static boolean suspendUser(String ApplicationRoot, String userId, int numberOfMinutes) {
log.debug("*** Setter.suspendUser ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Prepairing suspendUser call");
PreparedStatement callstmnt = conn.prepareCall("CALL suspendUser(?, ?)");
callstmnt.setString(1, userId);
callstmnt.setInt(2, numberOfMinutes);
log.debug("Executing suspendUser statement on id '" + userId + "'");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("suspendUser Failure: " + e.toString());
result = false;
}
log.debug("*** END suspendUser ***");
return result;
}
/**
* Revokes a suspension that may have been applied to a user
*
* @param ApplicationRoot Running context of application
* @param userId The Identifier of the user that will be released from suspension
* @return
*/
public static boolean unSuspendUser(String ApplicationRoot, String userId) {
log.debug("*** Setter.unSuspendUser ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Prepairing suspendUser call");
PreparedStatement callstmnt = conn.prepareCall("CALL unSuspendUser(?)");
callstmnt.setString(1, userId);
log.debug("Executing unSuspendUser statement on id '" + userId + "'");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("unSuspendUser Failure: " + e.toString());
result = false;
}
log.debug("*** END unSuspendUser ***");
return result;
}
/**
* Used to increment a users CSRF counter for CSRF levels.
*
* @param ApplicationRoot The current running context of the application.
* @param moduleId The identifier of the module to increment the counter of
* @param userId The user to be incremented
* @return Boolean reflecting the success of the operation
*/
public static boolean updateCsrfCounter(String ApplicationRoot, String moduleId, String userId) {
log.debug("*** Getter.updateCsrfCounter ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
CallableStatement callstmt = conn.prepareCall("call resultMessagePlus(?, ?)");
log.debug("Preparing resultMessagePlus procedure");
callstmt.setString(1, moduleId);
callstmt.setString(2, userId);
callstmt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("Could not execute resultMessagePlus: " + e.toString());
}
log.debug("*** END updateCsrfCounter ***");
return result;
}
/**
* @param ApplicationRoot The current running context of the application
* @param userName User name of the user
* @param currentPassword User's current password
* @param newPassword New password to use in update
* @return ResultSet that contains error details if not successful
*/
public static boolean updatePassword(
String ApplicationRoot, String userName, String currentPassword, String newPassword) {
log.debug("*** Setter.updatePassword ***");
boolean result = false;
Connection conn;
try {
conn = Database.getCoreConnection(ApplicationRoot);
} catch (SQLException e) {
log.debug("Could not get core connection: " + e.toString());
throw new RuntimeException(e);
}
log.debug("Checking current password");
String user[] = Getter.authUser(ApplicationRoot, userName, currentPassword);
if (user == null || user[0].isEmpty()) {
// Wrong password
log.debug("Current password incorrect!");
return false;
}
if (user != null && !user[0].isEmpty()) {
// Correct password, proceed
log.debug("Hashing password");
Argon2 argon2 = Argon2Factory.create();
String newHash = argon2.hash(10, 65536, 1, newPassword.toCharArray());
// TODO: wipe password from memory after hashing
log.debug("Preparing userPasswordChange call");
CallableStatement callstmnt;
try {
callstmnt = conn.prepareCall("call userPasswordChange(?, ?)");
callstmnt.setString(1, userName);
callstmnt.setString(2, newHash);
log.debug("Executing userPasswordChange");
callstmnt.execute();
result = true;
} catch (SQLException e) {
log.debug("Could not update password: " + e.toString());
throw new RuntimeException(e);
}
} else {
log.debug("Could not verify password!");
return false;
}
Database.closeConnection(conn);
log.debug("*** END updatePassword ***");
return result;
}
/**
* @param ApplicationRoot The current running context of the application
* @param userName User name of the user
* @param currentPassword User's current password
* @param newPassword New password to use in update
* @return ResultSet that contains error details if not successful
*/
public static boolean updateUsername(
String ApplicationRoot, String userName, String newUsername) {
log.debug("*** Setter.updateUsername ***");
boolean result = false;
log.debug("Preparing username change call from username " + userName + " to " + newUsername);
PreparedStatement prestmnt;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
prestmnt =
conn.prepareStatement(
"UPDATE users SET userName = ?, tempUsername = FALSE WHERE userName = ?;");
prestmnt.setString(1, newUsername);
prestmnt.setString(2, userName);
log.debug("Executing name change query");
prestmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.debug("Could not update username: " + e.toString());
throw new RuntimeException(e);
}
log.debug("*** END updateUsername ***");
return result;
}
/**
* Updates a player's password without needing the current password
*
* @param ApplicationRoot Running context of the applicaiton
* @param userId The user id of the user to update
* @param newPassword The new password to assign to the user
* @return
*/
public static boolean updatePasswordAdmin(
String ApplicationRoot, String userId, String newPassword) {
log.debug("*** Setter.updatePasswordAdmin ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Hashing password");
Argon2 argon2 = Argon2Factory.create();
String newHash = argon2.hash(10, 65536, 1, newPassword.toCharArray());
log.debug("Preparing userPasswordChangeAdmin call");
CallableStatement callstmnt = conn.prepareCall("call userPasswordChangeAdmin(?, ?)");
callstmnt.setString(1, userId);
callstmnt.setString(2, newHash);
log.debug("Executing userPasswordChangeAdmin");
callstmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("updatePasswordAdmin Failure: " + e.toString());
}
log.debug("*** END updatePasswordAdmin ***");
return result;
}
/**
* Updates a PLAYER's class identifier
*
* @param ApplicationRoot The current running context of the application
* @param classId New class to be assigned to
* @param playerId Player to be assigned to new class
* @return The userName that was updated
*/
public static String updatePlayerClass(String ApplicationRoot, String classId, String playerId) {
log.debug("*** Setter.updatePlayerClass ***");
String result = null;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing playerUpdateClass call");
CallableStatement callstmnt = conn.prepareCall("call playerUpdateClass(?, ?)");
callstmnt.setString(1, playerId);
callstmnt.setString(2, classId);
log.debug("Executing playerUpdateClass");
ResultSet resultSet = callstmnt.executeQuery();
resultSet.next();
result = resultSet.getString(1);
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("playerUpdateClass Failure: " + e.toString());
result = null;
}
log.debug("*** END updatePlayerClass ***");
return result;
}
/**
* Updates a PLAYER's class identifier to null
*
* @param ApplicationRoot The current running context of the application
* @param playerId The identifier of the player to be assigned to class NULL
* @return The userName that was updated
*/
public static String updatePlayerClassToNull(String ApplicationRoot, String playerId) {
log.debug("*** Setter.updatePlayerClassToNull ***");
String result = null;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing playerUpdateClassToNull call");
CallableStatement callstmnt = conn.prepareCall("call playerUpdateClassToNull(?)");
callstmnt.setString(1, playerId);
log.debug("Executing playerUpdateClassToNull");
ResultSet resultSet = callstmnt.executeQuery();
resultSet.next();
result = resultSet.getString(1);
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("updatePlayerClassToNull Failure: " + e.toString());
result = null;
}
log.debug("*** END updatePlayerClassToNull ***");
return result;
}
/**
* Updates a users result of a specific module
*
* @param ApplicationRoot The current running context of the application
* @param moduleId Identifier of the module the user is completing
* @param userId Identifier of the user completing the module
* @param extra The additional comments submitted in feedback by the user, or if CSRF, the attack
* string they used
* @param before The knowledge the user felt before they completed the level
* @param after The knowledge the user felt after they completed the level
* @param difficulty The difficulty the user felt they encountered
* @return The module name of the module completed by the user
*/
public static String updatePlayerResult(
String ApplicationRoot,
String moduleId,
String userId,
String extra,
int before,
int after,
int difficulty) {
log.debug("*** Setter.updatePlayerResult ***");
String result = null;
boolean isOpen;
Boolean isRunning;
try {
isOpen = CountdownHandler.isOpen();
isRunning = CountdownHandler.isRunning();
} catch (InvalidCountdownStateException e1) {
String message = "Countdown handler is in an invalid state.";
log.error(message);
throw new RuntimeException(message);
}
if (isRunning) {
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing userUpdateResult call");
CallableStatement callstmnt =
conn.prepareCall("call userUpdateResult(?, ?, ?, ?, ?, ?, ?)");
callstmnt.setString(1, moduleId);
callstmnt.setString(2, userId);
callstmnt.setInt(3, before);
callstmnt.setInt(4, after);
callstmnt.setInt(5, difficulty);
callstmnt.setBoolean(6, isOpen); // Only give points if CTF is open
callstmnt.setString(7, extra);
log.debug("Executing userUpdateResult");
callstmnt.execute();
// User Executed. Now Get the Level Name Langauge Key
result = Getter.getModuleNameLocaleKey(ApplicationRoot, moduleId);
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("userUpdateResult Failure: " + e.toString());
result = null;
}
} else {
log.error("Error: Can't allow results to be stored when CTF isn't running");
result = null;
}
log.debug("*** END updatePlayerResult ***");
return result;
}
/**
* Adds or Subtracts points from a user.
*
* @param ApplicationRoot Running context of application
* @param userId Identifier of user to update
* @param points Positive or Negative number of points to update by
* @return Returns true if statement executes without fatal error
*/
public static boolean updateUserPoints(String ApplicationRoot, String userId, int points) {
log.debug("*** Setter.updateUserPoints ***");
boolean result = false;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing updateUserPoints call");
PreparedStatement prestmnt =
conn.prepareStatement("UPDATE users SET userScore = userScore + ? WHERE userId = ?");
prestmnt.setInt(1, points);
prestmnt.setString(2, userId);
log.debug("Executing updateUserPoints");
prestmnt.execute();
result = true;
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("updateUserPoints Failure: " + e.toString());
}
log.debug("*** END updateUserPoints ***");
return result;
}
/**
* Updates a USER's role
*
* @param ApplicationRoot The current running context of the application
* @param playerId The identifier of the player to update
* @param newRole Must be "player" or "admin"
* @return The user name of the user updated
*/
public static String updateUserRole(String ApplicationRoot, String playerId, String newRole) {
log.debug("*** Setter.updateUserRole ***");
String result = null;
try {
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Preparing userUpdateRole call");
CallableStatement callstmnt = conn.prepareCall("call userUpdateRole(?, ?)");
callstmnt.setString(1, playerId);
callstmnt.setString(2, newRole);
log.debug("Executing userUpdateRole");
ResultSet resultSet = callstmnt.executeQuery();
resultSet.next();
result = resultSet.getString(1);
Database.closeConnection(conn);
} catch (SQLException e) {
log.error("userUpdateRole Failure: " + e.toString());
result = null;
}
log.debug("*** END updateUserRole ***");
return result;
}
/**
* Used by many functions to create players or admins
*
* @param ApplicationRoot
* @param classId Cannot be null, relationship depending
* @param userName Cannot be null
* @param userPass Cannot be null
* @param userRole Cannot be null, must be "player" or "admin"
* @param userAddress Must be unique
* @param tempPass Whether or not to set the user with a temporary pass flag
* @return A boolean value determining the result of the creation
* @throws SQLException If the creation fails, a Exception is thrown
*/
public static boolean userCreate(
String ApplicationRoot,
String classId,
String userName,
String userPass,
String userRole,
String userAddress,
boolean tempPass)
throws SQLException {
boolean result = false;
log.debug("*** Setter.userCreate ***");
log.debug("classId = " + classId);
log.debug("userName = " + userName);
// We don't log passwords
log.debug("userRole = " + userRole);
log.debug("userAddress = " + userAddress);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Hashing password");
Argon2 argon2 = Argon2Factory.create();
String hash = argon2.hash(10, 65536, 1, userPass.toCharArray());
// TODO: wipe password from memory after hashing
log.debug("Executing userCreate procedure on Database");
CallableStatement callstmt = conn.prepareCall("call userCreate(?, ?, ?, ?, ?, ?, ?, ?, ?)");
callstmt.setString(1, classId);
callstmt.setString(2, userName);
callstmt.setString(3, hash);
callstmt.setString(4, userRole);
callstmt.setString(5, null); // ssoName
callstmt.setString(6, userAddress);
callstmt.setString(7, "login"); // login type
callstmt.setBoolean(8, tempPass);
callstmt.setBoolean(9, false); // Tempname
ResultSet registerAttempt = callstmt.executeQuery();
log.debug("Opening result set");
registerAttempt.next(); // Procedure Ran correctly
if (registerAttempt.getString(1) == null) {
// Registration success
log.debug("Register Success");
result = true;
} else {
// Registration failure
result = false;
log.debug("ResultSet contained -> " + registerAttempt.getString(1));
throw new SQLException(registerAttempt.getString(1));
}
Database.closeConnection(conn);
log.debug("*** END userCreate ***");
return result;
}
public static String userCreateSSO(
String ApplicationRoot, String classId, String userName, String ssoName, String userRole)
throws SQLException {
String result = null;
log.debug("*** Setter.userCreateSSO ***");
log.debug("classId = " + classId);
log.debug("userName = " + userName);
log.debug("ssoName = " + ssoName);
// We don't log passwords
Connection conn = Database.getCoreConnection(ApplicationRoot);
String newUsername = userName;
try {
log.debug("Checking for duplicate usernames");
boolean isDuplicate = true;
int duplicateCounter = 0;
while (isDuplicate) {
PreparedStatement prestmt =
conn.prepareStatement("SELECT ssoName FROM `users` WHERE userName = ?");
prestmt.setString(1, newUsername);
ResultSet checkDuplicate = prestmt.executeQuery();
log.debug("Opening result set");
if (checkDuplicate.next()) {
// Found a duplicate user, sigh
isDuplicate = true;
duplicateCounter++;
newUsername = userName + String.valueOf(duplicateCounter);
log.debug(
"Duplicate username found, changing to "
+ newUsername
+ " counter "
+ String.valueOf(duplicateCounter));
} else {
isDuplicate = false;
}
if (duplicateCounter > 500) {
String message =
"Bailing out of the de-duplicate loop at " + String.valueOf(duplicateCounter);
log.error(message);
throw new RuntimeException(message);
}
}
} catch (SQLException e) {
log.fatal("Failed to check for duplicate usernames: " + e.toString());
throw new SQLException(e);
}
try {
log.debug("Executing userCreate procedure on Database");
CallableStatement callstmt = conn.prepareCall("call userCreate(?, ?, ?, ?, ?, ?, ?, ?, ?)");
callstmt.setString(1, classId);
callstmt.setString(2, newUsername);
callstmt.setString(3, "DISABLED");
callstmt.setString(4, userRole);
callstmt.setString(5, ssoName);
callstmt.setString(6, ""); // userAddress
callstmt.setString(7, "saml"); // login type
callstmt.setBoolean(8, false); // temppass
callstmt.setBoolean(9, true); // Tempname
ResultSet registerAttempt = callstmt.executeQuery();
log.debug("Opening result set");
registerAttempt.next(); // Procedure Ran correctly
if (registerAttempt.getString(1) == null) {
// Registration success
log.debug("Register Success");
result = newUsername;
} else {
// Registration failure
result = null;
log.debug("ResultSet contained -> " + registerAttempt.getString(1));
throw new SQLException(registerAttempt.getString(1));
}
} catch (SQLException e) {
log.fatal("userCreate Failure: " + e.toString());
throw new SQLException(e);
}
Database.closeConnection(conn);
log.debug("*** END userCreateSSO ***");
return result;
}
public static boolean userDelete(String ApplicationRoot, String userId) throws SQLException {
boolean result = false;
log.debug("*** Setter.userDelete ***");
log.debug("userId = " + userId);
Connection conn = Database.getCoreConnection(ApplicationRoot);
try {
log.debug("Deleting User's Results");
PreparedStatement callDelResults =
conn.prepareStatement("DELETE FROM results WHERE userId = ?");
callDelResults.setString(1, userId);
callDelResults.executeUpdate();
log.debug("Executing delete from users on Database");
PreparedStatement callUserDel = conn.prepareStatement("DELETE FROM users WHERE userId = ?");
callUserDel.setString(1, userId);
int deleteAttemptResult = callUserDel.executeUpdate();
if (deleteAttemptResult == 1) {
result = true;
}
} catch (SQLException sqlEx) {
log.fatal("userDelete Failure: " + sqlEx.toString());
throw new SQLException(sqlEx);
}
Database.closeConnection(conn);
log.debug("*** END userDelete ***");
return result;
}
public static boolean setAdminCheatStatus(String ApplicationRoot, boolean adminCheatsEnabled)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setAdminCheatStatus ***");
log.debug("adminCheatsEnabled = " + adminCheatsEnabled);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting admin cheat setting");
PreparedStatement callAdminSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
callAdminSetting.setBoolean(1, adminCheatsEnabled);
callAdminSetting.setString(2, "adminCheatsEnabled");
if (callAdminSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set admin cheat setting");
}
Database.closeConnection(conn);
log.debug("*** END setAdminCheatStatus ***");
return result;
}
public static boolean setPlayerCheatStatus(String ApplicationRoot, boolean playerCheatsEnabled)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setPlayerCheatStatus ***");
log.debug("playerCheatsEnabled = " + playerCheatsEnabled);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting player cheat setting");
PreparedStatement callPlayerSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
callPlayerSetting.setBoolean(1, playerCheatsEnabled);
callPlayerSetting.setString(2, "playerCheatsEnabled");
if (callPlayerSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set player cheat setting");
}
Database.closeConnection(conn);
log.debug("*** END setPlayerCheatStatus ***");
return result;
}
public static boolean setModuleLayout(String ApplicationRoot, String theModuleLayout)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setModulelayout ***");
log.debug("playerCheatsEnabled = " + theModuleLayout);
if (theModuleLayout != "ctf" && theModuleLayout != "tournament" && theModuleLayout != "open") {
throw new IllegalArgumentException("Invalid module layout: " + theModuleLayout);
}
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting player cheat setting");
PreparedStatement moduleLayoutSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
moduleLayoutSetting.setString(1, theModuleLayout);
moduleLayoutSetting.setString(2, "modulelayout");
if (moduleLayoutSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set module layout to " + theModuleLayout);
}
Database.closeConnection(conn);
log.debug("*** END setModulelayout ***");
return result;
}
public static boolean setFeedbackStatus(String ApplicationRoot, boolean theFeebackStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setFeedbackStatus ***");
log.debug("feedbackStatus = " + theFeebackStatus);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting feedback status setting");
PreparedStatement getFeedbackSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
getFeedbackSetting.setBoolean(1, theFeebackStatus);
getFeedbackSetting.setString(2, "enableFeedback");
int updateResult = getFeedbackSetting.executeUpdate();
if (updateResult == 1) {
result = true;
} else {
throw new RuntimeException("Could not set feedback status to " + theFeebackStatus);
}
Database.closeConnection(conn);
log.debug("*** END setFeedbackStatus ***");
return result;
}
public static boolean setRegistrationStatus(String ApplicationRoot, boolean theRegistrationStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setRegistrationStatus ***");
log.debug("enableRegistration = " + theRegistrationStatus);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting registration status setting");
PreparedStatement setRegistrationSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
setRegistrationSetting.setBoolean(1, theRegistrationStatus);
setRegistrationSetting.setString(2, "openRegistration");
if (setRegistrationSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set registration status to " + theRegistrationStatus);
}
Database.closeConnection(conn);
log.debug("*** END setRegistrationStatus ***");
return result;
}
public static boolean setScoreboardStatus(String ApplicationRoot, String theScoreboardStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setScoreboardStatus ***");
log.debug("scoreboardStatus = " + theScoreboardStatus);
if (theScoreboardStatus != "closed"
&& theScoreboardStatus != "adminOnly"
&& theScoreboardStatus != "classSpecific"
&& theScoreboardStatus != "open"
&& theScoreboardStatus != "public") {
throw new IllegalArgumentException("Invalid scoreboard status: " + theScoreboardStatus);
}
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting scoreboard status setting");
PreparedStatement scoreboardSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
scoreboardSetting.setString(1, theScoreboardStatus);
scoreboardSetting.setString(2, "scoreboardStatus");
if (scoreboardSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set scoreboard status to " + theScoreboardStatus);
}
Database.closeConnection(conn);
log.debug("*** END setScoreboardStatus ***");
return result;
}
public static boolean setScoreboardClass(String ApplicationRoot, String theScoreboardClass)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setScoreboardClass ***");
log.debug("scoreboardClass = " + theScoreboardClass);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting scoreboard class setting");
PreparedStatement scoreboardClassSetting =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
scoreboardClassSetting.setString(1, theScoreboardClass);
scoreboardClassSetting.setString(2, "scoreboardClass");
if (scoreboardClassSetting.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set scoreboard class to " + theScoreboardClass);
}
Database.closeConnection(conn);
log.debug("*** END setScoreboardClass ***");
return result;
}
public static boolean setStartTimeStatus(String ApplicationRoot, boolean theStartTimeStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setStartTimeStatus ***");
log.debug("theLockTimeStatus = " + theStartTimeStatus);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting start time setting");
PreparedStatement lockTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
lockTimeStatement.setBoolean(1, theStartTimeStatus);
lockTimeStatement.setString(2, "hasStartTime");
if (lockTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set start time status to " + theStartTimeStatus);
}
Database.closeConnection(conn);
log.debug("*** END setStartTimeStatus ***");
return result;
}
public static boolean setStartTime(String ApplicationRoot, LocalDateTime theStartTime)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setStartTime ***");
log.debug("theLockTime = " + theStartTime);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting start time");
PreparedStatement lockTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
lockTimeStatement.setString(1, theStartTime.toString());
lockTimeStatement.setString(2, "startTime");
if (lockTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set start time to " + theStartTime);
}
Database.closeConnection(conn);
log.debug("*** END setStartTime ***");
return result;
}
public static boolean setLockTimeStatus(String ApplicationRoot, boolean theLockTimeStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setLockTimeStatus ***");
log.debug("theLockTimeStatus = " + theLockTimeStatus);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting lock timestamp setting");
PreparedStatement lockTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
lockTimeStatement.setBoolean(1, theLockTimeStatus);
lockTimeStatement.setString(2, "hasLockTime");
if (lockTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set lock time status to " + theLockTimeStatus);
}
Database.closeConnection(conn);
log.debug("*** END setLockTimeStatus ***");
return result;
}
public static boolean setLockTime(String ApplicationRoot, LocalDateTime theLockTime)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setLockTime ***");
log.debug("theLockTime = " + theLockTime);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting lock time");
PreparedStatement lockTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
lockTimeStatement.setString(1, theLockTime.toString());
lockTimeStatement.setString(2, "lockTime");
if (lockTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set lock time to " + theLockTime);
}
Database.closeConnection(conn);
log.debug("*** END setLockTime ***");
return result;
}
public static boolean setEndTimeStatus(String ApplicationRoot, boolean theEndTimeStatus)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setEndTimeStatus ***");
log.debug("theEndTimeStatus = " + theEndTimeStatus);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting end time setting");
PreparedStatement lockTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
lockTimeStatement.setBoolean(1, theEndTimeStatus);
lockTimeStatement.setString(2, "hasEndTime");
if (lockTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set end time status to " + theEndTimeStatus);
}
Database.closeConnection(conn);
log.debug("*** END theEndTimeStatus ***");
return result;
}
public static boolean setEndTime(String ApplicationRoot, LocalDateTime theEndTime)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setEndTime ***");
log.debug("theLockTime = " + theEndTime);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting end time");
PreparedStatement endTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
endTimeStatement.setString(1, theEndTime.toString());
endTimeStatement.setString(2, "endTime");
if (endTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set end time to " + theEndTime);
}
Database.closeConnection(conn);
log.debug("*** END setEndTime ***");
return result;
}
public static boolean setDefaultClass(String ApplicationRoot, String theDefaultClass)
throws SQLException {
boolean result = false;
log.debug("*** Setter.setDefaultClass ***");
log.debug("theLockTime = " + theDefaultClass);
Connection conn = Database.getCoreConnection(ApplicationRoot);
log.debug("Setting default class");
PreparedStatement endTimeStatement =
conn.prepareStatement("UPDATE settings SET value = ? WHERE setting = ?");
endTimeStatement.setString(1, theDefaultClass);
endTimeStatement.setString(2, "defaultClass");
if (endTimeStatement.executeUpdate() == 1) {
result = true;
} else {
throw new RuntimeException("Could not set default class to " + theDefaultClass);
}
Database.closeConnection(conn);
log.debug("*** END setDefaultClass ***");
return result;
}
}