Skip to content
This repository was archived by the owner on Feb 27, 2025. It is now read-only.
This repository was archived by the owner on Feb 27, 2025. It is now read-only.

Update HpsTokenService to support SSL pinning #7

@anokmik

Description

@anokmik

Hello,

Please, update HpsTokenService to support SSL pinning. Updated implementation is provided below.

Thanks!

public class HpsTokenService {

    private String mPublicKey;
    private String mCertificateBase64EncodedPublicKey;
    private String mUrl;

    public HpsTokenService(String publicKey, String certificateBase64EncodedPublicKey) {
        mPublicKey = publicKey;
        mCertificateBase64EncodedPublicKey = certificateBase64EncodedPublicKey;

        if (publicKey == null) {
            throw new IllegalArgumentException("publicKey can not be null");
        }

        String[] components = mPublicKey.split("_");

        if (components.length < 3) {
            throw new IllegalArgumentException("publicKey format invalid");
        }

        String env = components[1].toLowerCase();

        if (env.equals("prod")) {
            mUrl = "https://api2.heartlandportico.com/SecureSubmit.v1/api/token";
        } else {
            mUrl = "https://cert.api2.heartlandportico.com/Hps.Exchange.PosGateway.Hpf.v1/api/token";
        }
    }

    public HpsToken getToken(HpsCreditCard card) throws IOException {
        HttpsURLConnection conn = (HttpsURLConnection) new URL(mUrl).openConnection();
        HpsToken result = null;

        byte[] creds = String.format("%s:", mPublicKey).getBytes();
        String auth = String.format("Basic %s", Base64.encodeBase64URLSafeString(creds));

        Gson gson = new Gson();
        String payload = gson.toJson(new HpsToken(card));

        byte[] bytes = payload.getBytes();

        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setRequestMethod("POST");
        conn.addRequestProperty("Authorization", auth);
        conn.addRequestProperty("Content-Type", "application/json");
        conn.addRequestProperty("Content-Length", String.format("%s", bytes.length));

        conn.connect();

        if (isSslPinningSuccessful(conn)) {
            DataOutputStream requestStream = new DataOutputStream(conn.getOutputStream());
            requestStream.write(bytes);
            requestStream.flush();
            requestStream.close();

            try {
                InputStreamReader responseStream = new InputStreamReader(conn.getInputStream());
                result = gson.fromJson(responseStream, HpsToken.class);
                responseStream.close();
            } catch (IOException e) {
                if (conn.getResponseCode() == 400) {
                    InputStreamReader errorStream = new InputStreamReader(conn.getErrorStream());
                    result = gson.fromJson(errorStream, HpsToken.class);
                    errorStream.close();
                } else {
                    throw new IOException(e);
                }
            }
        }

        return result;
    }

    private boolean isSslPinningSuccessful(HttpsURLConnection conn) {
        try {
            Certificate[] certs = conn.getServerCertificates();
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            for (Certificate cert : certs) {
                X509Certificate x509Certificate = (X509Certificate) cert;
                byte[] encodedPublicKey = x509Certificate.getPublicKey().getEncoded();
                byte[] encodedPublicKeySha256Bytes = md.digest(encodedPublicKey);
                String encodedPublicKeyBase64String = Base64.encodeBase64URLSafeString(encodedPublicKeySha256Bytes);
                if (mCertificateBase64EncodedPublicKey.equals(encodedPublicKeyBase64String)) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

}

Best regards,
Mikle Anokhin.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions