org.knowm.xchange.binance.service.BinanceHmacDigest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xchange-binance Show documentation
Show all versions of xchange-binance Show documentation
XChange implementation for the Binance Exchange
package org.knowm.xchange.binance.service;
import static org.knowm.xchange.utils.DigestUtils.bytesToHex;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import javax.crypto.Mac;
import javax.ws.rs.QueryParam;
import org.knowm.xchange.binance.BinanceAuthenticated;
import org.knowm.xchange.service.BaseParamsDigest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import si.mazi.rescu.Params;
import si.mazi.rescu.RestInvocation;
public class BinanceHmacDigest extends BaseParamsDigest {
private static final Logger LOG = LoggerFactory.getLogger(BinanceHmacDigest.class);
private final Field invocationUrlField;
private BinanceHmacDigest(String secretKeyBase64) {
super(secretKeyBase64, HMAC_SHA_256);
try {
invocationUrlField = RestInvocation.class.getDeclaredField("invocationUrl");
invocationUrlField.setAccessible(true);
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
public static BinanceHmacDigest createInstance(String secretKeyBase64) {
return secretKeyBase64 == null ? null : new BinanceHmacDigest(secretKeyBase64);
}
/** @return the query string except of the "signature" parameter */
private static String getQuery(RestInvocation restInvocation) {
final Params p = Params.of();
restInvocation.getParamsMap().get(QueryParam.class).asHttpHeaders().entrySet().stream()
.filter(e -> !BinanceAuthenticated.SIGNATURE.equals(e.getKey()))
.forEach(e -> p.add(e.getKey(), e.getValue()));
return p.asQueryString();
}
@Override
public String digestParams(RestInvocation restInvocation) {
try {
final String input;
if (restInvocation.getPath().startsWith("wapi/")) {
// little dirty hack for /wapi methods
input = getQuery(restInvocation);
} else {
switch (restInvocation.getHttpMethod()) {
case "GET":
case "DELETE":
input = getQuery(restInvocation);
break;
case "POST":
input = restInvocation.getRequestBody();
break;
default:
throw new RuntimeException(
"Not support http method: " + restInvocation.getHttpMethod());
}
}
Mac mac = getMac();
mac.update(input.getBytes("UTF-8"));
String printBase64Binary = bytesToHex(mac.doFinal());
// https://github.com/mmazi/rescu/issues/62
// Seems rescu does not support ParamsDigest in QueryParam.
// hack to replace the signature in the invocation URL.
String invocationUrl = restInvocation.getInvocationUrl();
// String newInvocationUrl = UriBuilder.fromUri(invocationUrl).replaceQueryParam("signature",
// printBase64Binary).build().toString();
final String sig = "signature=";
int idx = invocationUrl.indexOf(sig);
String newInvocationUrl = invocationUrl.substring(0, idx + sig.length()) + printBase64Binary;
try {
invocationUrlField.set(restInvocation, newInvocationUrl);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
return printBase64Binary;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Illegal encoding, check the code.", e);
}
}
}