package gp.e3.autheo.authentication.domain.business;

import gp.e3.autheo.authentication.domain.entities.User;
import gp.e3.autheo.authentication.domain.exceptions.TokenGenerationException;
import gp.e3.autheo.authentication.infrastructure.validators.StringValidator;

import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Random;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TokenFactory {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(TokenFactory.class);
	
	public static final int TOKEN_CHARACTER_LIMIT = 20;
	
	/**
	 * Calculate and return the hash of a given string using PBKDF2WithHmacSHA1.
	 * 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeySpecException 
	 */
	private static final String getHashFromString(String string) throws NoSuchAlgorithmException, InvalidKeySpecException {
		
		byte[] salt = new byte[16];
		
		Random random = new Random();
		random.nextBytes(salt);
		
		KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 128);
		SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
		byte[] hash = secretKeyFactory.generateSecret(spec).getEncoded();
		
		String stringHash = new BigInteger(1, hash).toString(16);
	
		return stringHash;
	}
	
	/**
	 * Generates the authentication token.
	 * 
	 * @param user, user information used to generate the token.
	 * @return A new authentication token. 
	 * @throws TokenGenerationException, exception thrown when there is an error generating the authentication token.
	 */
	public static final String getToken(User user) throws TokenGenerationException {

		String generatedToken = "";
		
		String username = user.getUsername();
		String password = user.getPassword();
		
		if ((user != null) && StringValidator.isValidString(username) && StringValidator.isValidString(password)) {
			
			long currentMillis = DateTime.now().getMillis();
			String baseForToken = currentMillis + username + password;
			
			try {
				
				generatedToken = getHashFromString(baseForToken).substring(0, TOKEN_CHARACTER_LIMIT);
				
			} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
				
				LOGGER.error("getToken", e);
				String errorMessage = "There was an error generating the authentication token.";
				throw new TokenGenerationException(errorMessage);
			}
			
		} else {
			
			String errorMessage = "The user given as argument is not valid.";
			throw new IllegalArgumentException(errorMessage);
		}
		
		return generatedToken;
	}
}
@@ -1882,24 +1882,51 @@
 en = %22%22;%0A%09%09%0A
+%09%09if (user != null) %7B%0A%09%09%09%0A%09
 %09%09String use
@@ -1955,16 +1955,17 @@
 me();%0A%09%09
+%09
 String p
@@ -2000,33 +2000,17 @@
 ;%0A%09%09
-%0A
+%09%0A%09
 %09%09if (
-(user != null) && 
 Stri
@@ -2094,17 +2094,19 @@
 )) %7B%0A%09%09%09
-%0A
+%09%0A%09
 %09%09%09long 
@@ -2145,24 +2145,25 @@
 etMillis();%0A
+%09
 %09%09%09String ba
@@ -2215,17 +2215,19 @@
 ord;%0A%09%09%09
-%0A
+%09%0A%09
 %09%09%09try %7B
@@ -2231,21 +2231,23 @@
 y %7B%0A%09%09%09%09
+%09
 %0A%09%09%09%09
+%09
 generate
@@ -2328,17 +2328,19 @@
 T);%0A%09%09%09%09
-%0A
+%09%0A%09
 %09%09%09%7D cat
@@ -2403,21 +2403,23 @@
 ) %7B%0A%09%09%09%09
+%09
 %0A%09%09%09%09
+%09
 LOGGER.e
@@ -2439,16 +2439,17 @@
 n%22, e);%0A
+%09
 %09%09%09%09Stri
@@ -2525,16 +2525,17 @@
 oken.%22;%0A
+%09
 %09%09%09%09thro
@@ -2580,16 +2580,168 @@
 ssage);%0A
+%09%09%09%09%7D%0A%09%09%09%09%0A%09%09%09%7D else %7B%0A%09%09%09%09%0A%09%09%09%09String errorMessage = %22The user given as argument is not valid.%22;%0A%09%09%09%09throw new IllegalArgumentException(errorMessage);%0A
 %09%09%09%7D%0A%09%09%09

Fix a bug related to the token generation.