Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package dhbw.clippinggorilla.objects.user; import com.vaadin.server.VaadinSession; import dhbw.clippinggorilla.external.database.Columns; import dhbw.clippinggorilla.external.database.Database; import dhbw.clippinggorilla.external.database.Tables; import dhbw.clippinggorilla.external.database.exceptions.PasswordChangeException; import dhbw.clippinggorilla.external.database.exceptions.UserCreationException; import dhbw.clippinggorilla.external.database.exceptions.UserNotFoundException; import dhbw.clippinggorilla.external.mailserver.Mail; import dhbw.clippinggorilla.objects.category.Category; import dhbw.clippinggorilla.objects.clipping.ClippingUtils; import dhbw.clippinggorilla.objects.group.Group; import dhbw.clippinggorilla.objects.group.GroupUtils; import dhbw.clippinggorilla.objects.interestprofile.InterestProfile; import dhbw.clippinggorilla.objects.interestprofile.InterestProfileUtils; import dhbw.clippinggorilla.objects.source.Source; import dhbw.clippinggorilla.scheduler.Jobs; import dhbw.clippinggorilla.utilities.database.SQLUtils; import dhbw.clippinggorilla.utilities.language.Language; import dhbw.clippinggorilla.utilities.language.Word; import dhbw.clippinggorilla.utilities.log.Log; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.LocalTime; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import org.apache.commons.mail.EmailException; import org.mindrot.jbcrypt.BCrypt; /** * * @author frank */ public class UserUtils { private static final HashMap<VaadinSession, User> USERS = new HashMap<>(); private static final HashMap<String, User> USERS_PER_USERNAME = new HashMap<>(); private static final HashMap<String, User> USERS_PER_EMAIL = new HashMap<>(); public static final HashMap<Integer, User> USERS_PER_ID = new HashMap<>(); /** * Returns the current User or null if there is no User logged in * * @return The requested User or null */ public static User getCurrent() { return USERS.get(VaadinSession.getCurrent()); } private static void addUser(User user) { USERS_PER_USERNAME.put(user.getUsername(), user); USERS_PER_EMAIL.put(user.getEmail(), user); USERS_PER_ID.put(user.getId(), user); } public static void setCurrentUser(User u) { VaadinSession session = VaadinSession.getCurrent(); if (session != null) { USERS.put(session, u); } } public static void removeCurrentUser() { VaadinSession session = VaadinSession.getCurrent(); USERS.remove(session); } /** * Get a User via given username or email * * @param input can be an email or username * @return The requested User (or a exception is thrown) */ public static User getUser(String input) throws UserNotFoundException { String sql; if (input.contains("@")) { if (USERS_PER_EMAIL.containsKey(input)) { User u = USERS_PER_EMAIL.get(input); addUser(u); return u; } sql = "SELECT * FROM " + Tables.USER + " WHERE " + Columns.EMAIL + " = ?"; } else { if (USERS_PER_USERNAME.containsKey(input)) { User u = USERS_PER_USERNAME.get(input); addUser(u); return u; } sql = "SELECT * FROM " + Tables.USER + " WHERE " + Columns.USERNAME + " = ?"; } User u = new User(); try { PreparedStatement stat = Database.getConnection().prepareStatement(sql); stat.setString(1, input); ResultSet result = stat.executeQuery(); if (result.next()) { u.setId(result.getInt(Columns.ID)); u.setUsername(result.getString(Columns.USERNAME)); u.setPassword(result.getString(Columns.PASSWORD)); u.setSalt(result.getString(Columns.SALT)); u.setEmail(result.getString(Columns.EMAIL)); u.setFirstName(result.getString(Columns.FIRST_NAME)); u.setLastName(result.getString(Columns.LAST_NAME)); u.setRegistrationDate(result.getTimestamp(Columns.REGISTRATION_DATE).toLocalDateTime()); u.setAccessLevel(result.getInt(Columns.STATUS)); u.setActivationKey(result.getString(Columns.ACTIVATION_KEY)); if (result.getInt(Columns.SEND_CLIPPING_MAIL) == 1) { u.setSendClippingMail(true); } else { u.setSendClippingMail(false); } u.setClippingTime(loadAllClippingSendTimes(u)); if (u.getClippingTime().size() < 1) { addClippingSendTime(u, LocalTime.of(8, 0)); } } else { throw new UserNotFoundException(); } } catch (SQLException ex) { throw new UserNotFoundException(); } UserUtils.addUser(u); u.setLastClipping(ClippingUtils.getLastClipping(u)); return u; } /** * Get a User via given id * * @param id The id of the requested User * @return The requested User (or a exception is thrown) */ public static User getUser(int id) throws UserNotFoundException { if (USERS_PER_ID.containsKey(id)) { User u = USERS_PER_ID.get(id); addUser(u); return u; } String sql = "SELECT * FROM " + Tables.USER + " WHERE " + Columns.ID + " = ?"; User u = new User(); try { PreparedStatement stat = Database.getConnection().prepareStatement(sql); stat.setInt(1, id); ResultSet result = stat.executeQuery(); if (result.next()) { u.setId(result.getInt(Columns.ID)); u.setUsername(result.getString(Columns.USERNAME)); u.setPassword(result.getString(Columns.PASSWORD)); u.setSalt(result.getString(Columns.SALT)); u.setEmail(result.getString(Columns.EMAIL)); u.setFirstName(result.getString(Columns.FIRST_NAME)); u.setLastName(result.getString(Columns.LAST_NAME)); u.setRegistrationDate(result.getTimestamp(Columns.REGISTRATION_DATE).toLocalDateTime()); u.setAccessLevel(result.getInt(Columns.STATUS)); u.setActivationKey(result.getString(Columns.ACTIVATION_KEY)); if (result.getInt(Columns.SEND_CLIPPING_MAIL) == 1) { u.setSendClippingMail(true); } else { u.setSendClippingMail(false); } u.setClippingTime(loadAllClippingSendTimes(u)); if (u.getClippingTime().size() < 1) { addClippingSendTime(u, LocalTime.of(8, 0)); } } else { throw new UserNotFoundException(); } } catch (SQLException ex) { throw new UserNotFoundException(); } UserUtils.addUser(u); u.setLastClipping(ClippingUtils.getLastClipping(u)); return u; } /** * Validates the user login attempt and return a user on success * * @param input email or username * @param password * @return HashMap<Integer, User> --> Integer values: 0: ID for * User // -1: User not found in DB // -2: Password doesn't match to * user/email // -3: User not activated // -4: User banned */ public static HashMap<Integer, User> loginUser(String input, String password) { User user = null; HashMap<Integer, User> returnMap = new HashMap<>(); try { user = UserUtils.getUser(input); } catch (UserNotFoundException ex) { returnMap.put(-1, user); return returnMap; } if (user.getPassword().equals(getEncryptedPassword(password, user.getSalt()))) { if (user.getAccessLevel() >= 20) { returnMap.put(0, user); return returnMap; } else if (user.getAccessLevel() >= 10) { returnMap.put(-3, user); return returnMap; } else { returnMap.put(-4, user); return returnMap; } } else { returnMap.put(-2, user); return returnMap; } } /** * Changes password (requires two times the new password) * * @param user The User whose password should be changed * * @param oldPassword The old password * @param newPassword The new password * @param newPassword2 The new password again to verify integrity * @return true: everything is ok, false: sth. went wrong */ public static synchronized boolean changePassword(User user, String oldPassword, String newPassword, String newPassword2) { if (user.getPassword().equals(getEncryptedPassword(oldPassword, user.getSalt())) && checkPassword(newPassword).length() == 0 && checkSecondPassword(newPassword, newPassword2).length() == 0) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.PASSWORD + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); String pw = getEncryptedPassword(newPassword, user.getSalt()); statement.setString(1, pw); statement.setInt(2, user.getId()); statement.executeUpdate(); user.setPassword(pw); return true; } catch (SQLException ex) { return false; } } return false; } /** * Change the first name of the user. * * @param u The User whose first name should be changed * @param newFirstName The new first name * @return true if change was successful, false if dberror occured or * requirements are not met. */ public static synchronized boolean changeFirstName(User u, String newFirstName) { if (checkName(newFirstName).length() == 0) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.FIRST_NAME + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setString(1, newFirstName); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setFirstName(newFirstName); return true; } catch (SQLException ex) { Log.warning("Failed to change first name!", ex); return false; } } return false; } /** * Change the last name of the user. * * @param u The User whose last name should be changed * @param newLastName The new last name * @return true if change was successful, false if dberror occured or * requirements are not met. */ public static synchronized boolean changeLastName(User u, String newLastName) { if (checkName(newLastName).length() == 0) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.LAST_NAME + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setString(1, newLastName); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setLastName(newLastName); return true; } catch (SQLException ex) { Log.warning("Failed to change first name!", ex); return false; } } return false; } /** * Changes email (requires two times the new email) * * @param u The User whose password should be changed * @param oldEmail The old mail * @param newEmail The new mail * @param newEmail2 The new mail again to verify integrity * @return true: everything is ok, false: sth. went wrong */ public static synchronized boolean changeEmail(User u, String oldEmail, String newEmail, String newEmail2) { if (!newEmail.equals(oldEmail) && checkEmail(newEmail).length() == 0 && checkSecondEmail(newEmail, newEmail2).length() == 0) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.EMAIL + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setString(1, newEmail); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setEmail(newEmail); return true; } catch (SQLException ex) { Log.warning("Failed to change first name!", ex); return false; } } return false; } /** * Changes the username of a User * * @param u The User whose Username should be changed * @param newUsername The new Username * @return true if successful, false otherwise */ public static synchronized boolean changeUsername(User u, String newUsername) { if (checkUsername(newUsername).length() == 0) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.USERNAME + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setString(1, newUsername); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setUsername(newUsername); return true; } catch (SQLException ex) { Log.warning("Failed to change first name!", ex); return false; } } return false; } /** * Returns true if activationKey is correct and updates AccessLevel to 20 * * @param u The User who should be activated * @param activationKey The key send via email to activate the user * @return true if the key is correct, false otherwise */ public static synchronized boolean activateUser(User u, String activationKey) { if (u.getActivationKey().equals(activationKey)) { try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.STATUS + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, 20); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setAccessLevel(20); return true; } catch (SQLException ex) { Log.warning("SQLException on account activation: ", ex); return false; } } else { Log.debug("Ceck failed, not equal!"); return false; } } /** * Sets status of user to 0, which effectively bans him. * * @param u The User sho sould be banned * @return true if successful, otherwise: false */ public static boolean banUser(User u) { Log.info("Banning user " + u.getUsername()); try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.STATUS + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, 0); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setAccessLevel(0); return true; } catch (SQLException ex) { Log.warning("Failed banning user " + u.getUsername(), ex); return false; } } /** * Sets status of user to 20, which effectively unbans him. * * @param u The User whose should be unbanned * @return true if successful, otherwise: false */ public static boolean pardonUser(User u) { Log.info("Pardoning user " + u.getUsername()); try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.STATUS + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, 20); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setAccessLevel(20); return true; } catch (SQLException ex) { Log.warning("Failed pardoning user " + u.getUsername(), ex); return false; } } /** * Sets status of user to 90, which effectively makes him a Admin. * * @param u The User who should be an admin * @return true if successful, otherwise: false */ public static boolean opUser(User u) { Log.info("Opping user " + u.getUsername()); try { String sql = "UPDATE " + Tables.USER + " SET " + Columns.STATUS + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, 90); statement.setInt(2, u.getId()); statement.executeUpdate(); u.setAccessLevel(90); return true; } catch (SQLException ex) { Log.warning("Failed opping user " + u.getUsername(), ex); return false; } } /** * Inserts a new user into the database if all requirements are met. This is * not a full registration as the user still has to confirm his mail. * * @param username The Username * @param password The first password * @param password2 The second password * @param email The first email * @param email2 The second email * @param firstName The first name * @param lastName The second name * @return The newly created User * @throws UserCreationException If the mail could not be send or some * values are illegal */ public static synchronized User registerUser(String username, String password, String password2, String email, String email2, String firstName, String lastName) throws UserCreationException { String salt = getSaltString(); String activationKey = createNewActivationKey(); //Backend check of user input to make sure that all values are within defined parameters if (checkUserGetBoolean(username, password, password2, email, email2, firstName, lastName)) { try { password = getEncryptedPassword(password, salt); String sql = "INSERT INTO " + Tables.USER + " ( " + Columns.USERNAME + ", " + Columns.SALT + ", " + Columns.PASSWORD + ", " + Columns.EMAIL + ", " + Columns.FIRST_NAME + ", " + Columns.LAST_NAME + ", " + Columns.ACTIVATION_KEY + ") VALUES (?, ?, ?, ?, ?, ?, ?);"; PreparedStatement sta = Database.getConnection().prepareStatement(sql); sta.setString(1, username); sta.setString(2, salt); sta.setString(3, password); sta.setString(4, email); sta.setString(5, firstName); sta.setString(6, lastName); sta.setString(7, activationKey); sta.executeUpdate(); Log.info("User creation: Successfully inserted new user to DB!"); User user = getUser(username); if (!sendRegistrationMail(user)) { throw new UserCreationException(""); } return user; } catch (SQLException ex) { Log.warning("User creation: Failed due to SQL error: " + ex); throw new UserCreationException("" + ex); } } else { Log.warning("User creation: Failed due to illegal values!"); throw new UserCreationException("User creation failed due to illegal values!"); } } /** * Removes a user * * @param u The User who should be deleted */ public static void removeUser(User u) { String sql = "DELETE FROM " + Tables.USER + " WHERE " + Columns.ID + " = ?"; try { PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Sql failed: removeUser", ex); } USERS.values().remove(u); USERS_PER_EMAIL.values().remove(u); USERS_PER_ID.values().remove(u); USERS_PER_USERNAME.values().remove(u); } /** * Sends a registration mail to a user * * @param user The User who should receive a registration mail * @return true if successfully send, false otherwise */ public static boolean sendRegistrationMail(User user) { Log.debug("Create key for user: " + user.getUsername() + " -- user.getActivationKey: " + user.getActivationKey()); String mail = Language.get(Word.HELLO) + " " + user.getFirstName() + " " + user.getLastName() + ", \n" + Language.get(Word.REGISTRATION_VERIFICATION_MAIL_INTRO) + user.getActivationKey() + Language.get(Word.REGISTRATION_VERIFICATION_MAIL_OUTRO); try { Mail.send(user.getEmail(), Language.get(Word.REGISTRATION_VERIFICATION_MAIL_SUBJECT), mail); return true; } catch (EmailException e) { Log.error("Could not send registration Email", e); return false; } } /** * Sends a new activation mail for the user. This also creates a new key. * * @param u The User whose activation key should be send again * @throws EmailException true if send successfully, false otherwise */ public static void resendActivationMail(User u) throws EmailException { setNewActivationKey(u); String mail = Language.get(Word.HELLO) + " " + u.getFirstName() + " " + u.getLastName() + ", \n" + Language.get(Word.REGISTRATION_VERIFICATION_MAIL_INTRO) + u.getActivationKey() + Language.get(Word.REGISTRATION_VERIFICATION_MAIL_OUTRO); try { Mail.send(u.getEmail(), Language.get(Word.REGISTRATION_VERIFICATION_MAIL_SUBJECT), mail); } catch (EmailException e) { Log.error("Could not resend activation email", e); } } private static String createNewActivationKey() { return getRandomIntAsString(6); } private static void setNewActivationKey(User u) { try { u.setActivationKey(getRandomIntAsString(6)); String sql = "UPDATE " + Tables.USER + " SET " + Columns.ACTIVATION_KEY + " = ? WHERE " + Columns.ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setString(1, u.getActivationKey()); statement.setInt(2, u.getId()); statement.executeUpdate(); } catch (SQLException ex) { Log.warning("activationKey upload failed: ", ex); } } private static String getRandomIntAsString(int length) { String token = ""; for (int i = 0; i < length; i++) { token += String.valueOf((int) (Math.random() * 10)); } if (token.length() > length) { token = token.substring(1, length); } return token; } /** * Checks all parameters whether they contain only allowed values for i.e. * registration. Use checkUserGetError to recieve the ErrorMessages! * * @param username The username * @param password The first password * @param password2 The second password * @param email The first email * @param email2 The second email * @param firstName The first name * @param lastName The last name * @return true when everything is ok, false when there is a error. */ public static boolean checkUserGetBoolean(String username, String password, String password2, String email, String email2, String firstName, String lastName) { return checkUserGetError(username, password, password2, email, email2, firstName, lastName).length() == 0; } /** * Checks all parameters whether they contain only allowed values for i.e. * registration and returns all errormessages (i.e.: username to long) * * @param username The username * @param password The first password * @param password2 The second password * @param email The first email * @param email2 The second email * @param firstName The first name * @param lastName The last name * @return all error messages */ public static String checkUserGetError(String username, String password, String password2, String email, String email2, String firstName, String lastName) { String errorCollection = ""; errorCollection += checkUsername(username); errorCollection += checkEmail(email); errorCollection += checkSecondEmail(email, email2); errorCollection += checkPassword(password); errorCollection += checkSecondPassword(password, password2); errorCollection += checkName(firstName); errorCollection += checkName(lastName); return errorCollection; } /** * Checks whether username is within given parameters * * @param username The username to be checked * @return error messages. If string is empty, everything is fine. */ public static String checkUsername(String username) { String returnMessage = checkUsernameOnFormalCorrectness(username); if (checkUsernameExisting(username)) { returnMessage += Language.get(Word.USERNAME_ALREADY_TAKEN) + "<br>"; } return returnMessage; } /** * Checks whether user already exists in database * * @param username The username to be checked * @return true if user exists */ public static boolean checkUsernameExisting(String username) { try { String sql = "SELECT * FROM " + Tables.USER + " WHERE " + Columns.USERNAME + " = ?"; PreparedStatement stat = Database.getConnection().prepareStatement(sql); stat.setString(1, username); return stat.executeQuery().next(); } catch (SQLException ex) { Log.warning("SQL failed on check whether user exists", ex); return false; } } /** * Only checks whether username isn't too long/short enough and is formal * correct * * @param username The username to be checked * @return error Messages */ public static String checkUsernameOnFormalCorrectness(String username) { String returnMessage = ""; if (username.length() > 20) { returnMessage += Language.get(Word.USERNAME_TO_LONG) + "<br>"; } if (username.length() < 3) { returnMessage += Language.get(Word.USERNAME_TO_SHORT) + "<br>"; } if (!Pattern.compile("[a-zA-Z0-9_-]*").matcher(username).matches()) { returnMessage += Language.get(Word.USERNAME_FORBIDDEN_CHARACTERS) + "<br>"; } return returnMessage; } /** * Checks whether E-Mail address is within given parameters * * @param email The email to be checked * @return error messages. If string is empty, everything is fine. */ public static String checkEmail(String email) { String returnMessage = checkEmailOnFormalCorrectness(email); if (checkEmailExisting(email)) { returnMessage += Language.get(Word.EMAIL_ALREADY_TAKEN) + "<br>"; } if (Mail.isChunk(email)) { returnMessage += Language.get(Word.JUNK_MAIL_NOT_ALLOWED); } return returnMessage; } /** * Only checks whether email is long enough and is formal correct * * @param email The email to be checked * @return error messages. If string is empty everything is fine. */ public static String checkEmailOnFormalCorrectness(String email) { String returnMessage = ""; String regex = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"; if (!email.matches(regex)) { returnMessage += Language.get(Word.EMAIL_WRONG_INPUT) + "<br>"; } if (email.length() > 255) { returnMessage += Language.get(Word.EMAIL_TO_LONG) + "<br>"; } return returnMessage; } /** * Checks whether email already exists in database * * @param email The email to be checked * @return true if mail exists */ public static boolean checkEmailExisting(String email) { try { String sql = "SELECT * FROM " + Tables.USER + " WHERE " + Columns.EMAIL + " = ?"; PreparedStatement stat = Database.getConnection().prepareStatement(sql); stat.setString(1, email); return stat.executeQuery().next(); } catch (SQLException ex) { Log.warning("SQL failed on check whether user exists", ex); return false; } } /** * Checks whether both emails are equal * * @param email The first email * @param email2 The second email * @return error messages. If string is empty, everything is fine. */ public static String checkSecondEmail(String email, String email2) { String returnMessage = ""; if (!email.equals(email2)) { returnMessage += Language.get(Word.EMAILS_DONT_MATCH) + "<br>"; } return returnMessage; } /** * Checks password on length and characters used * * @param password The password to be checked * @return error messages. If string is empty, everything is fine. */ public static String checkPassword(String password) { String returnMessage = ""; if (password.length() > 50) { returnMessage += Language.get(Word.PASSWORD_TO_LONG) + "<br>"; } if (password.length() < 8) { returnMessage += Language.get(Word.PASSWORD_TO_SHORT) + "<br>"; } if (!Pattern.compile("[()@!$%&/=,-:_#.+\\w]*").matcher(password).matches()) { returnMessage += Language.get(Word.PASSWORD_REGEX_RULES) + "<br>"; } return returnMessage; } /** * Checks equality of both passwords * * @param password The first password * @param password2 The second password * @return error messages. If string is empty, everything is fine. */ public static String checkSecondPassword(String password, String password2) { String returnMessage = ""; if (!password.equals(password2)) { returnMessage += Language.get(Word.PASSWORDS_DONT_MATCH) + "<br>"; } return returnMessage; } /** * Estimates the strength of a password based on the parameters length and * types of used characters. * * @param password The password to be calculated * @return percentage of a float between 0 and 1 */ public static float calculatePasswordStrength(String password) { float strength = 0; if (password.length() <= 20 && password.length() >= 8) { strength = (float) ((password.length() - 8) / 32.0); } else if (password.length() > 20) { strength = (float) 0.5; } if (password.matches(".*[@!$%&/=,-:_#.+].*")) { strength += 0.2; } if (password.matches(".*[a-z].*")) { strength += 0.1; } if (password.matches(".*[A-Z].*")) { strength += 0.1; } if (password.matches(".*[0-9].*")) { strength += 0.1; } if (strength > 1) { strength = 1; } return strength; } /** * Initiates the recovery of a forgotten password by sending recoverymail * and creating a recovery token. A token is only working during a single * session and is not saved to the database. * * @param input email or username * @return authenticationToken or null if user wasn't found */ public static String initiateForgottenPasswordRecovery(String input) { User user = getUser(input); String authenticationToken = getRandomIntAsString(6); String body = authenticationToken; //Make this better : Log.debug("passwordrecovery key: " + authenticationToken); try { Mail.send(user.getEmail(), Language.get(Word.FORGOTTEN_PASSWORD_MAIL_SUBJECT), body); } catch (EmailException ex) { Log.warning("Password recovery mail sending failed.", ex); return ""; } return authenticationToken; } /** * Changes the password of the user specified via email. If anything fails, * a exception is thrown, as every error should be caught before using this * method! * * @param input - email or user * @param usersAuthenticationKey * @param generatedAuthenticationKey * @param password1 The new first password * @param password2 The new second password * @throws * dhbw.clippinggorilla.external.database.exceptions.PasswordChangeException */ public static void executeForgottenPasswordRecovery(String input, String usersAuthenticationKey, String generatedAuthenticationKey, String password1, String password2) throws PasswordChangeException { String salt = getSaltString(); User user = getUser(input); if (checkPassword(password1).length() == 0 && checkSecondPassword(password1, password2).length() == 0 && usersAuthenticationKey.equals(generatedAuthenticationKey)) { try { password1 = getEncryptedPassword(password1, salt); String sql = "UPDATE " + Tables.USER + " SET " + Columns.SALT + " = ?, " + Columns.PASSWORD + " = ? WHERE " + Columns.EMAIL + " = ?"; Log.debug(sql); PreparedStatement sta = Database.getConnection().prepareStatement(sql); sta.setString(1, salt); sta.setString(2, password1); sta.setString(3, user.getEmail()); sta.executeUpdate(); } catch (SQLException ex) { Log.warning("Password recovery failed at SQL UPDATE: ", ex); throw new PasswordChangeException(); } } else { throw new PasswordChangeException(); } } /** * Checks if first and lastname are ok. * * @param name The name to be checked * @return error messages. If string is empty, everything is fine. */ public static String checkName(String name) { String returnMessage = ""; if (name.length() > 30) { returnMessage += Language.get(Word.NAME_TO_LONG) + "<br>"; } if (name.length() < 2) { returnMessage += Language.get(Word.NAME_TO_SHORT) + "<br>"; } if (!Pattern.compile("[a-zA-Z\\t\\n\\x0B\\f\\r-.]*").matcher(name).matches()) { returnMessage += Language.get(Word.NAME_FORBIDDEN_CHARACTERS) + "<br>"; } return returnMessage; } private static String getEncryptedPassword(String passwordToHash, String salt) { return BCrypt.hashpw(passwordToHash, salt); } private static String getSaltString() { return BCrypt.gensalt(); } /** * Creates a new User Profile and saves it to the DB * * @param u The User of the new Interestprofile * @param name The name of the Interestprofile * @param sources The selected sources * @param tags The selected tags * @param categories The selected categories * @return Profile, if sth. went wrong: null */ public static InterestProfile createNewProfile(User u, String name, Map<Source, Boolean> sources, Set<String> tags, Map<Category, Boolean> categories) { //TODO: profile validation here! //Valdiation whether profile exists if (!InterestProfileUtils.checkNameUnique(u, name)) { return null; } try { //Insert profile data to user_profile table String sql = "INSERT INTO " + Tables.USER_PROFILE + " (" + Columns.USER_ID + ", " + Columns.NAME + ") VALUES (?, ?)"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); statement.setString(2, name); statement.executeUpdate(); //Get profile ID from table sql = "SELECT " + Columns.ID + " FROM " + Tables.USER_PROFILE + " WHERE " + Columns.USER_ID + " = ? AND " + Columns.NAME + " = ?"; statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); statement.setString(2, name); ResultSet result = statement.executeQuery(); result.next(); int profileId = result.getInt(Columns.ID); //Insert sources sources.forEach((lambda_source, bool) -> { if (bool == true) { String sourceId = lambda_source.getId(); try { String lambda_sql = "INSERT INTO " + Tables.USER_PROFILE_SOURCE + " (" + Columns.PROFILE_ID + ", " + Columns.SOURCE + ") VALUES (?, ?)"; PreparedStatement lambda_statement = Database.getConnection().prepareStatement(lambda_sql); lambda_statement.setInt(1, profileId); lambda_statement.setString(2, sourceId); lambda_statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Profile source insertion failed", ex); } } }); //Insert Tags tags.forEach((lambda_tags) -> { try { String lambda_sql = "INSERT INTO " + Tables.USER_PROFILE_TAG + " (" + Columns.PROFILE_ID + ", " + Columns.TAG + ") VALUES (?, ?)"; PreparedStatement lambda_statement = Database.getConnection().prepareStatement(lambda_sql); lambda_statement.setInt(1, profileId); lambda_statement.setString(2, lambda_tags); lambda_statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Profile source insertion failed", ex); } }); //Insert categories categories.forEach((category, bool) -> { if (bool == true) { String categoryId = category.getId(); try { String lambda_sql = "INSERT INTO " + Tables.USER_PROFILE_CATEGORY + " (" + Columns.PROFILE_ID + ", " + Columns.CATEGORY + ") VALUES (?, ?)"; PreparedStatement lambda_statement = Database.getConnection().prepareStatement(lambda_sql); lambda_statement.setInt(1, profileId); lambda_statement.setString(2, categoryId); lambda_statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Profile source insertion failed", ex); } } }); return InterestProfileUtils.getInterestProfile(profileId); } catch (SQLException ex) { Log.warning("Insertion of new profile failed", ex); return null; } } /** * Returns all Userprofiles of the user. * * @param u The User whose Interestprofiles should be returned * @return all user profiles in a Set or null if sth. went wrong */ public static Set<InterestProfile> getAllInterestProfiles(User u) { try { String sql = "SELECT " + Columns.ID + " FROM " + Tables.USER_PROFILE + " WHERE " + Columns.USER_ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); ResultSet result = statement.executeQuery(); Set<InterestProfile> profileSet = new HashSet<>(); while (result.next()) { profileSet.add(InterestProfileUtils.getInterestProfile(result.getInt(Columns.ID))); } return profileSet; } catch (SQLException ex) { Log.warning("Multiprofile selection failed", ex); return null; } } /** * Sets sendMail to true/false. * * @param u The User who should be changed * @param sendMail true if sending, false otherwise * @return true if successful */ public static boolean setEmailNewsletter(User u, boolean sendMail) { String sql = "UPDATE " + Tables.USER + " SET " + Columns.SEND_CLIPPING_MAIL + " = ? WHERE " + Columns.ID + " = ?"; try { PreparedStatement statement = Database.getConnection().prepareStatement(sql); if (!sendMail) { statement.setInt(1, 0); } else { statement.setInt(1, 1); } statement.setInt(2, u.getId()); statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Sql failed: setEmailNewsletter", ex); return false; } u.setSendClippingMail(sendMail); return true; } /** * Returns the value whether a clipping mail shall be send * * @param u The User to be changed * @return true == send; false == don't send */ public static boolean getEmailNewsletter(User u) { String sql = "SELECT " + Columns.SEND_CLIPPING_MAIL + " FROM " + Tables.USER + " WHERE " + Columns.ID + " = ?"; try { PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); ResultSet result = statement.executeQuery(); if (result.next()) { if (result.getInt(Columns.SEND_CLIPPING_MAIL) == 1) { u.setSendClippingMail(true); } else { u.setSendClippingMail(false); } } return u.isSendClippingMail(); } catch (SQLException ex) { Log.warning("Sql failed: getEmailNewsletter", ex); return u.isSendClippingMail(); } } /** * Adds a new Clipping sending time for a User * * @param u The User of the new Clipping sending time * @param time The Time of the clipping being send * @return true if successful, false otherwise */ public static boolean addClippingSendTime(User u, LocalTime time) { try { String sql = "INSERT INTO " + Tables.USER_CLIPPING_TIMES + " (" + Columns.USER_ID + ", " + Columns.CLIPPING_TIME + ") VALUES (?, ?)"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); statement.setString(2, time.toString()); statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Sql failed: addClippingTime", ex); return false; } u.getClippingTime().add(time); Jobs.updateClippingGenerationTimes(u, u.getClippingTime()); return true; } private static Set<LocalTime> loadAllClippingSendTimes(User u) { Set<LocalTime> times = new HashSet<>(); try { String sql = "SELECT * FROM " + Tables.USER_CLIPPING_TIMES + " WHERE " + Columns.USER_ID + " = ?"; PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); ResultSet result = statement.executeQuery(); while (result.next()) { times.add(LocalTime.parse(result.getString(Columns.CLIPPING_TIME))); } } catch (SQLException ex) { Log.warning("Sql failed: loadClippingTime", ex); } return times; } /** * removes a clipping send time from the users set. * * @param u The User which Clipping sending time should be removed * @param time time to remove, has to be in the users ClippingSendTimes! * @return true if successful */ public static boolean removeClippingSendTime(User u, LocalTime time) { if (u.getClippingTime().contains(time)) { String sql = "DELETE FROM " + Tables.USER_CLIPPING_TIMES + " WHERE " + Columns.USER_ID + " = ? AND " + Columns.CLIPPING_TIME + " = ?"; try { PreparedStatement statement = Database.getConnection().prepareStatement(sql); statement.setInt(1, u.getId()); statement.setString(2, time.toString()); statement.executeUpdate(); } catch (SQLException ex) { Log.warning("Sql failed: deleteClippingTime", ex); return false; } u.getClippingTime().remove(time); Jobs.updateClippingGenerationTimes(u, u.getClippingTime()); return true; } return false; } /** * Returns all Clipping sending times for all users * * @return The Times for all users */ public static Map<User, Set<LocalTime>> getAllClippingSendTimesForAllUsers() { String sql = "SELECT * FROM " + Tables.USER_CLIPPING_TIMES + " ORDER BY " + Columns.USER_ID; Map<User, Set<LocalTime>> allClippingTimes = new HashMap<>(); try { Statement statement = Database.getConnection().createStatement(); ResultSet result = statement.executeQuery(sql); while (result.next()) { User user = getUser(result.getInt(Columns.USER_ID)); LocalTime userTime = LocalTime.parse(result.getString(Columns.CLIPPING_TIME)); if (allClippingTimes.containsKey(user)) { allClippingTimes.get(user).add(userTime); } else { HashSet<LocalTime> userTimes = new HashSet<>(); userTimes.add(userTime); allClippingTimes.put(user, userTimes); } } } catch (SQLException ex) { Log.warning("Sql failed: getAllClippingTime", ex); } return allClippingTimes; } /** * Returns all the Groups for a User * * @param user * @return */ public static Set<Group> getAllGroups(User user) { Set<Group> userGroups = new LinkedHashSet<>(); try { ResultSet result = SQLUtils.SELECT(Columns.GROUP_ID_COLUMN).FROM(Tables.USER_GROUPS_TABLE) .WHERE(Columns.USER_ID_COLUMN, user.getId()).execute(); while (result.next()) { userGroups.add(GroupUtils.getGroup(result.getInt(Columns.GROUP_ID))); } } catch (SQLException ex) { Log.error("Could not get Groups for User", ex); } return userGroups; } }