Webhook Validation Demo
Last updated
Last updated
Demo for []
Please fill in your own info in the following codes.
package onramp.webhookvalidation;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
/**
* SignUtil
*
* @author FaTPay
*/
public class SignUtil {
private static final Logger LOG = LoggerFactory.getLogger(SignUtil.class);
/**
* Signature algorithms
*/
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
/**
* Webhook public key
*/
private static final String FATPAY_PUBLIC_KEY = "<FaTPay RSA PUBLIC KEY>";
/**
* Verifies the signature
*
* @param params
* @param rsaPublic
* @return
*/
public static Boolean rsaVerify(Map<String, String> params, String rsaPublic, String presign, String sign) {
try {
rsaPublic = StringUtils.replace(rsaPublic, "-----BEGIN PUBLIC KEY-----", "");
rsaPublic = StringUtils.replace(rsaPublic, "-----END PUBLIC KEY-----", "");
return doVerify(presign + paramsToStr(params), sign, rsaPublic);
} catch (Exception e) {
return false;
}
}
/**
* Verifies the signature
*
* @param content
* @param sign
* @param publicKey
* @return
*/
public static boolean doVerify(String content, String sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decodeBase64(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(content.getBytes(StandardCharsets.UTF_8));
return signature.verify(Base64.decodeBase64(sign));
} catch (Exception ex) {
LOG.error("éĒįžå¤ąč´Ĩīŧcontent={}", content, ex);
throw new IllegalArgumentException("rsa verify fail");
}
}
/**
* Converts parameters into ordered strings
*
* @param params
* @return
*/
private static String paramsToStr(Map<String, String> params) {
StringBuilder param = new StringBuilder();
List<String> keys = new ArrayList(params.keySet());
// Sorts the specified keys
Collections.sort(keys);
int index = 0;
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = params.get(key);
// Filter out null and empty values
if ("x-fp-signature".equals(key) || "signature".equals(key) || "sign".equals(key) || StringUtils.isBlank(value)) {
continue;
}
param.append(index == 0 ? "" : "&").append(key).append("=").append(value);
index++;
}
return param.toString();
}
/**
* Returns URI
*
* @param url
* @return
*/
public static URI getURI(String url) {
if (!(StringUtils.startsWithIgnoreCase(url, "http://") || StringUtils
.startsWithIgnoreCase(url, "https://"))) {
url = "http://" + url;
}
try {
URI uri = new URI(url);
return uri;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// ******************** WEBHOOK DEMO START ********************//
@PostMapping("/webhook_sign_verify")
public String webhookSignVerify(@RequestBody Map<String, String> requestBody, HttpServletRequest request) {
String signature = request.getHeader("X-FP-Signature");
// Converts header keys to lower case
Map<String, String> headers = new HashMap<>();
headers.put("x-fp-timestamp", request.getHeader("X-FP-Timestamp"));
headers.put("x-fp-nonce", request.getHeader("X-FP-Nonce"));
headers.put("x-fp-partner-id", request.getHeader("X-FP-Partner-Id"));
Map<String, String> params = new HashMap<>();
params.putAll(requestBody);
params.putAll(headers);
String url = request.getRequestURL().toString();
URI uri = SignUtil.getURI(url);
String presign = request.getMethod() + uri.getHost() + request.getRequestURI() + "?";
Boolean verified = false;
try {
verified = SignUtil.rsaVerify(params, FATPAY_PUBLIC_KEY, presign, signature);
} catch (Exception e) {
e.printStackTrace();
}
if (!verified) {
return "Signature error";
}
// do something
return "success";
}
// ******************** WEBHOOK DEMO END ********************//
}
const crypto = require('crypto');
var text = "original text to be signed"
var publickey = "public key to verify sign"
// verify signature
var verifier = crypto.createVerify("RSA-SHA256");
verifier.update(text);
result = verifier.verify(publickey, signature, "base64");
console.log("verify result: " + result)