Skip to content

Commit

Permalink
1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
Osiris-Team committed Mar 20, 2021
1 parent bf782fb commit 871702f
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.osiris.payhook</groupId>
<artifactId>PayHook</artifactId>
<version>1.4</version>
<version>1.5</version>
<packaging>jar</packaging>

<name>PayHook</name>
Expand Down
15 changes: 8 additions & 7 deletions src/main/java/com/osiris/payhook/PayHook.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ public String validateAndGet(Map<String, String> map, String key) throws ParseHe
}

/**
* See {@link #validateWebHookEvent(WebhookEvent)} (WebHookEvent)} for details.
* See {@link #validateWebhookEvent(WebhookEvent)} (WebHookEvent)} for details.
* @param validId your webhooks valid id. Get it from here: https://developer.paypal.com/developer/applications/
* @param validTypes your webhooks valid types/names. Here is a full list: https://developer.paypal.com/docs/api-basics/notifications/webhooks/event-names/
* @param header the http messages header as string.
* @param body the http messages body as string.
*/
public void validateWebHookEvent(String validId, List<String> validTypes, WebhookEventHeader header, String body) throws ParseBodyException, WebHookValidationException, CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException, SignatureException, InvalidKeyException {
validateWebHookEvent(new WebhookEvent(validId, validTypes, header, body));
public void validateWebhookEvent(String validId, List<String> validTypes, WebhookEventHeader header, String body) throws ParseBodyException, WebHookValidationException, CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException, SignatureException, InvalidKeyException {
validateWebhookEvent(new WebhookEvent(validId, validTypes, header, body));
}

/**
Expand All @@ -102,7 +102,7 @@ public void validateWebHookEvent(String validId, List<String> validTypes, Webhoo
* @throws WebHookValidationException if validation failed. IMPORTANT: MESSAGE MAY CONTAIN SENSITIVE INFORMATION!
* @throws ParseBodyException
*/
public void validateWebHookEvent(WebhookEvent event) throws WebHookValidationException, ParseBodyException, IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
public void validateWebhookEvent(WebhookEvent event) throws WebHookValidationException, ParseBodyException, IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
WebhookEventHeader header = event.getHeader();

// Check if the webhook types match
Expand Down Expand Up @@ -149,8 +149,9 @@ public void validateWebHookEvent(WebhookEvent event) throws WebHookValidationExc
String expectedSignature = String.format("%s|%s|%s|%s", transmissionId, transmissionTime, validWebhookId, SSLUtil.crc32(bodyString));

// Compare the encoded signature with the expected signature
String decodedSignature = SSLUtil.validateAndGetSignatureAsString(clientCerts, authAlgo, actualSignatureEncoded, expectedSignature);
if (decodedSignature!=null){
String decodedSignature = SSLUtil.decodeTransmissionSignature(actualSignatureEncoded);
boolean isSigValid = SSLUtil.validateTransmissionSignature(clientCerts, authAlgo, actualSignatureEncoded, expectedSignature);
if (isSigValid){
String[] arrayDecodedSignature = decodedSignature.split("\\|"); // Split by | char
header.setWebhookId(arrayDecodedSignature[2]);
header.setCrc32(arrayDecodedSignature[3]);
Expand All @@ -160,7 +161,7 @@ public void validateWebHookEvent(WebhookEvent event) throws WebHookValidationExc
throw new WebHookValidationException("Provided webhook id("+header.getWebhookId()+") does not match the valid id("+event.getValidWebHookId()+")!");
}
else
throw new WebHookValidationException("Transmission signature is not valid!");
throw new WebHookValidationException("Transmission signature is not valid! Expected: '"+expectedSignature+"' Provided: '"+decodedSignature+"'");
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/osiris/payhook/WebhookEventHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public String getTimestamp() {

/**
* IMPORTANT: SINCE THE WEBHOOK ID IS INSIDE THE ENCRYPTED TRANSMISSION SIGNATURE, THIS RETURNS NULL
* UNLESS YOU SUCCESSFULLY EXECUTED {@link PayHook#validateWebHookEvent(WebhookEvent)} ONCE BEFORE!
* UNLESS YOU SUCCESSFULLY EXECUTED {@link PayHook#validateWebhookEvent(WebhookEvent)} ONCE BEFORE!
* The ID of the webhook resource for the destination URL to which PayPal delivers the event notification.
*/
public String getWebhookId() {
Expand All @@ -50,7 +50,7 @@ public void setWebhookId(String webhookId) {

/**
* IMPORTANT: SINCE THE CRC32 IS INSIDE THE ENCRYPTED TRANSMISSION SIGNATURE, THIS RETURNS NULL
* UNLESS YOU SUCCESSFULLY EXECUTED {@link PayHook#validateWebHookEvent(WebhookEvent)} ONCE BEFORE!
* UNLESS YOU SUCCESSFULLY EXECUTED {@link PayHook#validateWebhookEvent(WebhookEvent)} ONCE BEFORE!
* The Cyclic Redundancy Check (CRC32) checksum for the body of the HTTP payload.
*/
public String getCrc32() {
Expand Down
23 changes: 12 additions & 11 deletions src/main/java/com/osiris/payhook/paypal/SSLUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,27 +149,28 @@ public static long crc32(String data) {
*
* @param clientCerts Client Certificates
* @param algo Algorithm used for signature creation by server
* @param actualSignatureEncoded Paypal-Transmission-Sig header value passed by server
* @param expectedSignature Signature generated by formatting data with CRC32 value of request body
* @return the decoded signature as string if it is valid, null otherwise
* @param actualEncodedSignature Paypal-Transmission-Sig header value passed by server
* @param expectedDecodedSignature Signature generated by formatting data with CRC32 value of request body
* @return Returns true if signature is valid
*
* @throws NoSuchAlgorithmException
* @throws SignatureException
* @throws InvalidKeyException
*/
public static String validateAndGetSignatureAsString(Collection<X509Certificate> clientCerts, String algo,
String actualSignatureEncoded, String expectedSignature) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
public static boolean validateTransmissionSignature(Collection<X509Certificate> clientCerts, String algo,
String actualEncodedSignature, String expectedDecodedSignature) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
// Get the signatureAlgorithm from the PAYPAL-AUTH-ALGO HTTP header
Signature signatureAlgorithm = Signature.getInstance(algo);
// Get the certData from the URL provided in the HTTP headers and cache it
X509Certificate[] clientChain = clientCerts.toArray(new X509Certificate[0]);
signatureAlgorithm.initVerify(clientChain[0].getPublicKey());
signatureAlgorithm.update(expectedSignature.getBytes());
signatureAlgorithm.update(expectedDecodedSignature.getBytes());
// Actual signature is base 64 encoded and available in the HTTP headers
byte[] actualSignature = Base64.decodeBase64(actualSignatureEncoded.getBytes());
if (signatureAlgorithm.verify(actualSignature))
return new String(actualSignature);
else
return null;
byte[] actualSignature = Base64.decodeBase64(actualEncodedSignature.getBytes());
return signatureAlgorithm.verify(actualSignature);
}

public static String decodeTransmissionSignature(String encodedSignature){
return new String(Base64.decodeBase64(encodedSignature.getBytes()));
}
}

0 comments on commit 871702f

Please sign in to comment.