com.board.games.handler.xbtit.XbtitPokerLoginServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.board.games.handler.xbtit.XbtitPokerLoginServiceImpl.java

Source

/**
 * This file is part of Boardservice Software package.
 * @copyright (c) 2014 Cuong Pham-Minh
 *
 * Boardservice is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License, version 2 (GPL-2.0)
 * as published by the Free Software Foundation.
 *
 * This program 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.
 *
 * A copy of the license can be viewed in the docs/LICENSE.txt file.
 * The same can be viewed at <http://opensource.org/licenses/gpl-2.0.php>
 */
package com.board.games.handler.xbtit;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.atomic.AtomicInteger;

import com.board.games.service.wallet.WalletAdapter;

import org.apache.log4j.Logger;
import org.ini4j.Ini;
import org.mindrot.jbcrypt.BCrypt;

import com.board.games.config.ServerConfig;
import com.cubeia.firebase.api.action.local.LoginRequestAction;
import com.cubeia.firebase.api.action.local.LoginResponseAction;
import com.cubeia.firebase.api.login.LoginHandler;
import com.cubeia.firebase.api.service.ServiceRouter;
import com.board.games.handler.generic.PokerConfigHandler;

import org.apache.commons.lang.StringEscapeUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;

public class XbtitPokerLoginServiceImpl extends PokerConfigHandler implements LoginHandler {
    private static final int PHP_VERSION = 4;
    private String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    private static AtomicInteger pid = new AtomicInteger(0);
    private Logger log = Logger.getLogger(this.getClass());
    private ServiceRouter router;
    private static Connection connect = null;
    private static Statement statement = null;
    // private static PreparedStatement preparedStatement = null;
    private static ResultSet resultSet = null;
    private String connectionStr = "";
    private String jdbcDriverClassName = "";
    private String dbPrefix = "";
    private boolean needAgeAgreement = false;
    private int authTypeId = 1;

    protected void initialize() {
        super.initialize();
        try {
            Ini ini = new Ini(new File("JDBCConfig.ini"));
            String jdbcDriver = ini.get("JDBCConfig", "jdbcDriver");
            String connectionUrl = ini.get("JDBCConfig", "connectionUrl");
            String database = ini.get("JDBCConfig", "database");
            dbPrefix = ini.get("JDBCConfig", "dbPrefix");
            String user = ini.get("JDBCConfig", "user");
            String password = ini.get("JDBCConfig", "password");
            jdbcDriverClassName = ini.get("JDBCConfig", "driverClassName");
            connectionStr = "jdbc" + ":" + jdbcDriver + "://" + connectionUrl + "/" + database + "?user=" + user
                    + "&password=" + password;
            String forceAgeAgreement = ini.get("JDBCConfig", "forceAgeAgreement");
            if (!forceAgeAgreement.equals("") && "Y".equals(forceAgeAgreement.toUpperCase())) {
                needAgeAgreement = true;
            }

        } catch (IOException ioe) {
            log.error("Exception in initialize " + ioe.toString());
        } catch (Exception e) {
            log.error("Exception in initialize " + e.toString());
        }
    }

    @Override
    public LoginResponseAction handle(LoginRequestAction req) {
        // Must be the very first call
        initialize();
        boolean userHasAcceptedAgeclause = false;
        log.debug("Data login " + req.getData());
        int count = 0;
        int idx = 0;
        int ref = 0;
        StringBuffer sb = new StringBuffer();
        for (byte b : req.getData()) {
            idx++;
            log.debug((char) b);
            char val = (char) b;
            //   if (idx >7 )
            sb.append(val);

        }
        //log.debug("count " + count);
        // TO DBG: activate trace of detail array below
        log.debug("sb " + sb.toString());
        String logindataRequest = sb.toString();
        log.debug("logindataRequest" + logindataRequest);
        if (logindataRequest.toUpperCase().equals("AGEVERIFICATIONDONE")) {
            userHasAcceptedAgeclause = true;
        }
        LoginResponseAction response = null;
        try {

            String userIdStr = authenticate(req.getUser(), req.getPassword(), getServerCfg(),
                    userHasAcceptedAgeclause, authTypeId);
            if (!userIdStr.equals("")) {
                response = new LoginResponseAction(Integer.parseInt(userIdStr) > 0 ? true : false,
                        (req.getUser().toUpperCase().startsWith("GUESTXDEMO") ? req.getUser() + "_" + userIdStr
                                : req.getUser()),
                        Integer.parseInt(userIdStr)); // pid.incrementAndGet()
                return response;
            }
        } catch (SQLException sqle) {
            log.error("Error authenticate", sqle);
            response = new LoginResponseAction(false, -1);
            response.setErrorMessage(getSystemErrorMessage(sqle));
            response.setErrorCode(getSystemErrorCode(sqle));
            log.error(sqle);
        } catch (Exception e) {
            log.error("Error system", e);
        }

        response = new LoginResponseAction(false, -1);
        response.setErrorMessage(getNotFoundErrorMessage());
        response.setErrorCode(getNotFoundErrorCode());
        return response;
    }

    /**
     * This method should return the error code to send back if the sql query
     * fails. Default msg is 0.
     * 
     * @param e
     *            The sql exception, never null
     * @return The system error code
     */
    protected int getSystemErrorCode(SQLException e) {
        return 0;
    }

    /**
     * This method should return the error message to send back if the sql query
     * fails. Default msg is "System error."
     * 
     * @param e
     *            The sql exception, never null
     * @return The system error message
     */
    protected String getSystemErrorMessage(SQLException e) {
        return "System error.";
    }

    /**
     * This method should return the error code to send back if the sql query
     * does not get any results. Default msg is 0.
     * 
     * @return The "user not found" error code
     */
    protected int getNotFoundErrorCode() {
        return 0;
    }

    /**
     * This method should return the message to send back if the sql query does
     * not get any results. Default msg is "User not found."
     * 
     * @return The "user not found" error message, may be null
     */
    protected String getNotFoundErrorMessage() {
        return "User not found or registered but at least 1 post is required to play.";
    }

    private String authenticate(String user, String password, ServerConfig serverConfig, boolean checkAge,
            int authTypeId) throws Exception {
        try {
            if (serverConfig == null) {
                log.error("ServerConfig is null.");
                return "-3";
            }
            int idx = user.indexOf("_");
            if (idx != -1) {
                // let bots through
                String idStr = user.substring(idx + 1);
                if (user.toUpperCase().startsWith("BOT")) {
                    if (serverConfig.isUseIntegrations()) {
                        WalletAdapter walletAdapter = new WalletAdapter();
                        log.debug("Calling createWalletAccount");
                        //walletAdapter.createWalletAccount(new Long(String.valueOf(member_id)));
                        Long userId = walletAdapter.checkCreateNewUser(idStr, idStr, "UNUSED", new Long(0),
                                serverConfig.getCurrency(), serverConfig.getWalletBankAccountId(),
                                (serverConfig.getInitialAmount().multiply(new BigDecimal(20))), true, false, 0);
                        return String.valueOf(userId);
                    } else {
                        return idStr;
                    }

                }
            }
            if (user.toUpperCase().startsWith("GUESTXDEMO")) {
                return String.valueOf(pid.incrementAndGet());
            }
            log.debug("loading class name " + jdbcDriverClassName);
            // This will load the MySQL driver, each DB has its own driver
            // "com.mysql.jdbc.Driver"
            Class.forName(jdbcDriverClassName);
            // Setup the connection with the DB
            // "jdbc:mysql://localhost/dbName?" + "user=&password=");
            //log.debug("connectionStr " + connectionStr);
            connect = DriverManager.getConnection(connectionStr);

            // Statements allow to issue SQL queries to the database
            log.debug("calling createstatement");
            statement = connect.createStatement();
            log.debug("Execute query: authenticate");

            String selectSQL = "select id, username, salt, id_level, " + " password, pass_type,  "
                    + " random, dupe_hash from " + dbPrefix + "users " + " where username  = " + "\'" + user + "\'";
            log.debug("Executing query : " + selectSQL);
            resultSet = statement.executeQuery(selectSQL);
            String checkPwdHash = null;
            String checkPwdHashNew = null;
            String members_pass_hash = null;
            int posts = 0;
            int member_id = 0;
            if (resultSet != null && resultSet.next()) {
                member_id = resultSet.getInt("id");

                String members_display_name = resultSet.getString("username");
                members_pass_hash = resultSet.getString("password");

                log.error("DB members_pass_hash = " + members_pass_hash);
                String escapePwdHTML = StringEscapeUtils.escapeHtml(password);
                //      log.debug("escapeHTML = " + escapePwdHTML);
                String pwdMD5 = getMD5(escapePwdHTML);
                log.debug("pwdMD5 = " + pwdMD5);
                //         posts = resultSet.getInt("user_posts");
                //         log.debug("# of Post " + posts);
                boolean authenticated = false;

                if (serverConfig != null) {

                    log.debug("User: " + user + " Password " + "********");

                    // whoelse = $H$9G7SmcSl2EYeV3n49s9ronMpYGayL61
                    if (pwdMD5 != null && members_pass_hash != null) {
                        authenticated = true;
                    }

                } else {
                    log.error("ServerConfig is null.");
                    return "-3";
                }
                if (authenticated) {
                    log.debug("Authentication successful");

                    //         log.debug("Member id " + String.valueOf(member_id));

                    if (serverConfig.isUseIntegrations()) {

                        WalletAdapter walletAdapter = new WalletAdapter();
                        log.error("Calling createWalletAccount");
                        Long userId = walletAdapter.checkCreateNewUser(String.valueOf(member_id),
                                members_display_name, "UNUSED", new Long(1), serverConfig.getCurrency(),
                                serverConfig.getWalletBankAccountId(), serverConfig.getInitialAmount(), checkAge,
                                needAgeAgreement, authTypeId);
                        if (userId < 0) {
                            // user did not accept age clauses
                            return "-5";
                        }
                        log.debug("assigned new id as #" + String.valueOf(userId));
                        return String.valueOf(userId);
                    } else {
                        return String.valueOf(member_id);
                    }

                    /*                  if (posts >= 1) {
                                         return String.valueOf(member_id);
                                      } else {
                                         log.error("Required number of posts not met, denied login");
                                         return "-2";
                                      }*/
                } else {
                    log.error("hash not matched for user " + user + " password " + password);
                    return "-1";
                }

            } else {
                log.error("resultset is null " + selectSQL);
            }

        } catch (Exception e) {
            log.error("Error : " + e.toString());
            // throw e;
        } finally {
            close();
        }
        return "-3";
    }

    private void close() {
        try {
            if (resultSet != null) {
                resultSet.close();
            }

            if (statement != null) {
                statement.close();
            }

            if (connect != null) {
                connect.close();
            }
        } catch (Exception e) {

        }
    }

    /**
     * Port of Xbtit password handling to Java. 
        
     * See Xbtit/includes/functions.php
     * 
     * @author lars
     */

    public String phpbb_hash(String password) {
        String random_state = unique_id();
        String random = "";
        int count = 6;

        if (random.length() < count) {
            random = "";

            for (int i = 0; i < count; i += 16) {
                random_state = md5(unique_id() + random_state);
                random += pack(md5(random_state));
            }
            random = random.substring(0, count);
        }

        String hash = _hash_crypt_private(password, _hash_gensalt_private(random, itoa64));
        if (hash.length() == 34)
            return hash;

        return md5(password);
    }

    private String unique_id() {

        return unique_id("c");
    }

    // global $config;
    // private boolean dss_seeded = false;

    private String unique_id(String extra) {
        // TODO Generate something random here.
        return "1234567890abcdef";

    }

    private String _hash_gensalt_private(String input, String itoa64) {
        return _hash_gensalt_private(input, itoa64, 6);
    }

    private String _hash_gensalt_private(String input, String itoa64, int iteration_count_log2) {

        if (iteration_count_log2 < 4 || iteration_count_log2 > 31) {
            iteration_count_log2 = 8;
        }

        String output = "$H$";
        output += itoa64.charAt(Math.min(iteration_count_log2 +

                ((PHP_VERSION >= 5) ? 5 : 3), 30));
        output += _hash_encode64(input, 6);

        return output;
    }

    /**
     * Encode hash
     */
    private String _hash_encode64(String input, int count) {

        String output = "";
        int i = 0;

        do {
            int value = input.charAt(i++);
            output += itoa64.charAt(value & 0x3f);

            if (i < count)
                value |= input.charAt(i) << 8;

            output += itoa64.charAt((value >> 6) & 0x3f);

            if (i++ >= count)
                break;

            if (i < count)
                value |= input.charAt(i) << 16;

            output += itoa64.charAt((value >> 12) & 0x3f);

            if (i++ >= count)
                break;

            output += itoa64.charAt((value >> 18) & 0x3f);
        } while (i < count);

        return output;
    }

    String _hash_crypt_private(String password, String setting) {

        String output = "*";

        // Check for correct hash
        if (!setting.substring(0, 3).equals("$H$"))
            return output;

        int count_log2 = itoa64.indexOf(setting.charAt(3));

        if (count_log2 < 7 || count_log2 > 30)
            return output;

        int count = 1 << count_log2;
        String salt = setting.substring(4, 12);
        if (salt.length() != 8)
            return output;

        String m1 = md5(salt + password);
        String hash = pack(m1);
        do {
            hash = pack(md5(hash + password));
        } while (--count > 0);

        output = setting.substring(0, 12);

        output += _hash_encode64(hash, 16);

        return output;
    }

    public boolean phpbb_check_hash(String password, String hash) {
        if (hash.length() == 34)
            return _hash_crypt_private(password, hash).equals(hash);

        else
            return md5(password).equals(hash);
    }

    public static String md5(String data) {
        try {
            byte[] bytes = data.getBytes("ISO-8859-1");
            MessageDigest md5er = MessageDigest.getInstance("MD5");

            byte[] hash = md5er.digest(bytes);
            return bytes2hex(hash);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);

        }
    }

    static int hexToInt(char ch) {
        if (ch >= '0' && ch <= '9')
            return ch - '0';

        ch = Character.toUpperCase(ch);
        if (ch >= 'A' && ch <= 'F')

            return ch - 'A' + 0xA;

        throw new IllegalArgumentException("Not a hex character: " + ch);
    }

    private static String bytes2hex(byte[] bytes) {
        StringBuffer r = new StringBuffer(32);

        for (int i = 0; i < bytes.length; i++) {
            String x = Integer.toHexString(bytes[i] & 0xff);
            if (x.length() < 2)
                r.append("0");
            r.append(x);
        }
        return r.toString();

    }

    static String pack(String hex) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < hex.length(); i += 2) {
            char c1 = hex.charAt(i);
            char c2 = hex.charAt(i + 1);
            char packed = (char) (hexToInt(c1) * 16 + hexToInt(c2));

            buf.append(packed);
        }
        return buf.toString();
    }

    private synchronized String getMD5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes("UTF-8"));
            BigInteger number = new BigInteger(1, messageDigest);
            String hashtext = number.toString(16);
            // Now we need to zero pad it if you actually want the full 32
            // chars.
            while (hashtext.length() < 32) {
                hashtext = "0" + hashtext;
            }
            return hashtext;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        }
        return null;
    }

}