/*
* The MtGox-Java API is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The MtGox-Java API 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
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with the MtGox-Java API . If not, see <http://www.gnu.org/licenses/>.
*/
package to.sparks.mtgox.net;
import biz.source_code.base64Coder.Base64Coder;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang.StringUtils;
/**
* A simple implementation of an authenticated client for the MtGox HTTP API
*
* @author SparksG
*/
public class HTTPAuthenticator {
private String apiKey;
private String secret;
protected static Logger logger;
private int readTimout = 600000;
private int connectTimeout = 10000;
private int killTimeout = 600000;
public HTTPAuthenticator(final Logger logger, String apiKey, String secret) {
this.apiKey = apiKey;
this.secret = secret;
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
logger.log(Level.SEVERE, null, e);
}
}
/*
* This function is based on an original idea by github user christopherobin
* See https://gist.github.com/2396722
*/
protected InputStream getMtGoxHTTPInputStream(String path, HashMap<String, String> args) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
HttpURLConnection connection;
args.put("nonce", String.valueOf(System.nanoTime()));
String post_data = buildQueryString(args);
System.setProperty("jsse.enableSNIExtension", "false");
URL queryUrl = new URL(path);
connection = (HttpURLConnection) queryUrl.openConnection();
connection.setDoOutput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimout);
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; mtgox-java client)");
new Thread(new InterruptThread(Thread.currentThread(), connection)).start(); // Kill the connection on timeout
if (StringUtils.isNotBlank(this.secret) && !this.secret.equalsIgnoreCase("${api.secret}")) {
Mac mac = Mac.getInstance("HmacSHA512");
SecretKeySpec secret_spec = new SecretKeySpec(Base64Coder.decode(this.secret), "HmacSHA512");
mac.init(secret_spec);
String signature = new String(Base64Coder.encode(mac.doFinal(post_data.getBytes()))).replaceAll("\n", "");
connection.setRequestProperty("Rest-Key", apiKey);
connection.setRequestProperty("Rest-Sign", signature);
}
connection.getOutputStream().write(post_data.getBytes());
return connection.getInputStream();
}
protected InputStream getMtGoxHTTPInputStream(String path) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
return getMtGoxHTTPInputStream(path, new HashMap<String, String>());
}
private static String buildQueryString(HashMap<String, String> args) throws UnsupportedEncodingException {
String result = new String();
for (String hashkey : args.keySet()) {
if (result.length() > 0) {
result += '&';
}
result += URLEncoder.encode(hashkey, "UTF-8") + "="
+ URLEncoder.encode(args.get(hashkey), "UTF-8");
}
return result;
}
public int getReadTimout() {
return readTimout;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setReadTimout(int readTimout) {
this.readTimout = readTimout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/*
* http://thushw.blogspot.hu/2010/10/java-urlconnection-provides-no-fail.html
*/
class InterruptThread implements Runnable {
Thread parent;
HttpURLConnection con;
public InterruptThread(Thread parent, HttpURLConnection con) {
this.parent = parent;
this.con = con;
}
public void run() {
try {
Thread.sleep(killTimeout);
if (con != null) {
con.disconnect();
}
} catch (InterruptedException | NullPointerException e) {
}
}
}
}