package org.greenstone.catalina;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

// log4j threw class-not-found exception => tomact not set up with this jar?
//import org.apache.log4j.Logger;
// so, work with java built-in version
import java.util.logging.Logger;
    
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.mindrot.jbcrypt.BCrypt;

import org.apache.catalina.CredentialHandler;

/*
  To access the userName info in the WordPress database 'wordpress_tera'
  for the Database System's user 'wpuser_tera' (who effectively has admin
  abilities over the tables in the database)
  
    mysql -u wpuser_tera -p wordpress_tera

*/

/*

CREATE OR REPLACE VIEW wp_user_roles AS
SELECT u.user_login AS user_name, 'administrator' AS role
  FROM wp_users u
  JOIN wp_usermeta m ON m.user_id = u.ID
 WHERE m.meta_key = 'wp_capabilities'
   AND m.meta_value LIKE '%"administrator";b:1%'
UNION ALL
SELECT u.user_login, 'editor'
  FROM wp_users u
  JOIN wp_usermeta m ON m.user_id = u.ID
 WHERE m.meta_key = 'wp_capabilities'
   AND m.meta_value LIKE '%"editor";b:1%'
UNION ALL
SELECT u.user_login, 'author'
  FROM wp_users u
  JOIN wp_usermeta m ON m.user_id = u.ID
 WHERE m.meta_key = 'wp_capabilities'
   AND m.meta_value LIKE '%"author";b:1%'
UNION ALL
SELECT u.user_login, 'contributor'
  FROM wp_users u
  JOIN wp_usermeta m ON m.user_id = u.ID
 WHERE m.meta_key = 'wp_capabilities'
   AND m.meta_value LIKE '%"contributor";b:1%'
UNION ALL
SELECT u.user_login, 'subscriber'
  FROM wp_users u
  JOIN wp_usermeta m ON m.user_id = u.ID
 WHERE m.meta_key = 'wp_capabilities'
   AND m.meta_value LIKE '%"subscriber";b:1%';
*/

/*
	Check this with:

SELECT * FROM wp_user_roles;
*/




public class WordpressCredentialHandler implements CredentialHandler
{
    //static Logger logger = Logger.getLogger(WordpressCredentialHandler.class.getName());
    static Logger logger = Logger.getLogger(WordpressCredentialHandler.class.getName());
    
    static {
	logger.info("WordpressCredentialHandler loaded");
    }

    private String prehash(String password) throws Exception
    {
	// Matched to do the same pre-hash that pluggable.php in WordPress does
	// before it calls the built-in PHP function password_hash()
	
        Mac mac = Mac.getInstance("HmacSHA384");
        mac.init(new SecretKeySpec("wp-sha384".getBytes(StandardCharsets.UTF_8), "HmacSHA384"));

        byte [] hmac = mac.doFinal(password.getBytes(StandardCharsets.UTF_8));

	String base64_prehash = Base64.getEncoder().encodeToString(hmac); // standard RFC4648 Base64
	
        return base64_prehash;
    }


    @Override
    public boolean matches(String inputPassword, String storedHash)
    {
	// Initial version of code produced by ChatGPT
	///  After looking at the WordPress PHP code for password checking, this method
	//   was then manually updated with a prehash step, to match what the WordPress PHP code does	
	
	//logger.fine("WordpressCredentialHandler::matches()");
	//logger.fine(" inputPassword=" + inputPassword + ", storedHash=" + storedHash);
	
        if (inputPassword == null || storedHash == null) {
	    //logger.fine("=> returning false");
	    return false;
	}

	String prehash_input_password = null;
	try {
	    prehash_input_password = prehash(inputPassword);
	}
	catch (Exception e) {
	    e.printStackTrace();
	}

		    
        // bcrypt family ($2y$, $2a$, $2b$)
	// Wordpress generated ($wp$2y$)
	// => some string manipulation needed, before passing to Bcrypt()
	
        if (storedHash.startsWith("$wp$2")) {
	    // Remove the '$wp' at the start => that's a WordPress thing no something jBCrypt expects
            // jBCrypt also expects $2a/$2b; $2y is compatible → normalize
	    
            String normalised_stored_hash = storedHash.replaceFirst("^\\$wp\\$", "\\$").replaceFirst("^\\$2y\\$", "\\$2a\\$");
	    //logger.fine("  norm="+normalised_stored_hash);

	
            try {
		//logger.fine("  Checking with BCrypt");
		
		boolean match_check = BCrypt.checkpw(prehash_input_password, normalised_stored_hash);
		//logger.fine("  match_check = " + match_check);
		
                return match_check;
            } catch (IllegalArgumentException e) {
		logger.severe("  IllegalArgumentException!!");
                return false;
            }
        }
	else {
	    logger.warning("WordPressCredentialHandler::matches() - storedHash '"+storedHash+"' does not start $wp$2");
	}

        // Unknown format
        return false;
    }

    @Override
    public String mutate(String inputPassword) {
        // ChatGPT comment in generating this code:
	//   Only used if the Realm generates new hashes itself.
        //   WordPress normally handles this in PHP.

	// Code was then manually updated to match the prehash step in matches()

	System.err.println("**** WordpressCredentialHandler::mutate() - written but never used!");
	
	String prehash_input_password = null;
	try {
	    prehash_input_password = prehash(inputPassword);
	}
	catch (Exception e) {
	    e.printStackTrace();
	}

	
        return BCrypt.hashpw(prehash_input_password, BCrypt.gensalt(12));
    }
}
