Skip to content

Commit

Permalink
Feature/DEV-23903 Changes getHeadersV2 parameter to path instead of u…
Browse files Browse the repository at this point in the history
…rl (#155)

* DEV-23903 Transition from header V1 to header V2

* DEV-23903 remove unused import

* DEV-23903 Changes getHeadersV2 parameter to path instead of uri

* DEV-23903 Changes parameter name uri to path

* DEV-23903 Adds response checksum signature

* DEV-23903 Changes response field checksum to signature

---------

Co-authored-by: Abdurrahman Basgoynuk <[email protected]>
  • Loading branch information
abdurrahman98 and Abdurrahman Basgoynuk authored Sep 17, 2024
1 parent a47ebd2 commit 60a73df
Show file tree
Hide file tree
Showing 84 changed files with 624 additions and 204 deletions.
13 changes: 13 additions & 0 deletions src/main/java/com/iyzipay/HashValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.iyzipay;


import org.apache.commons.lang3.StringUtils;

public class HashValidator {
private HashValidator() {
}

public static boolean hashValid(String calculatedHash, String hash) {
return StringUtils.equals(calculatedHash, hash);
}
}
15 changes: 6 additions & 9 deletions src/main/java/com/iyzipay/IyziAuthV2Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ public final class IyziAuthV2Generator {
private IyziAuthV2Generator() {
}

public static String generateAuthContent(String uri, String apiKey, String secretKey, String randomString, Object request) {
public static String generateAuthContent(String path, String apiKey, String secretKey, String randomString, Object request) {
try {
String input = "apiKey:" + apiKey + "&randomKey:" + randomString + "&signature:" + getHmacSHA256Signature(uri, secretKey, randomString, request);
String input = "apiKey:" + apiKey + "&randomKey:" + randomString + "&signature:" + getHmacSHA256Signature(path, secretKey, randomString, request);
return DatatypeConverter.printBase64Binary(input.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new HttpClientException("Authentication content couldn't be generated", e);
}
}

private static String getHmacSHA256Signature(String uri, String secretKey, String randomString, Object request) {
private static String getHmacSHA256Signature(String path, String secretKey, String randomString, Object request) {
try {
String dataToSign = randomString + getPayload(uri, request);
String dataToSign = randomString + getPayload(path, request);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256"));
return DatatypeConverter.printHexBinary(mac.doFinal(dataToSign.getBytes("UTF-8"))).toLowerCase();
Expand All @@ -39,10 +39,7 @@ private static String getHmacSHA256Signature(String uri, String secretKey, Strin
}
}

private static String getPayload(String uri, Object request) {
int startIndex = uri.indexOf("/v2");
int endIndex = uri.indexOf("?");
String uriPath = endIndex == -1 ? uri.substring(startIndex) : uri.substring(startIndex, endIndex);
return request == null ? uriPath : uriPath + new Gson().toJson(request);
private static String getPayload(String path, Object request) {
return request == null ? path : path + new Gson().toJson(request);
}
}
12 changes: 8 additions & 4 deletions src/main/java/com/iyzipay/IyzipayResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class IyzipayResource {
private static final String CLIENT_VERSION_HEADER_NAME = "x-iyzi-client-version";
private static final String IYZIWS_HEADER_NAME = "IYZWS ";
private static final String IYZIWS_V2_HEADER_NAME = "IYZWSv2 ";
private static final String AUTHORIZATION_FALLBACK_HEADER = "Authorization_Fallback";
private static final String CLIENT_VERSION = IyzipayResource.class.getPackage().getImplementationVersion();
private static final String CLIENT_TITLE = IyzipayResource.class.getPackage().getImplementationTitle();
private static final String COLON = ":";
Expand All @@ -36,6 +37,7 @@ public class IyzipayResource {
public IyzipayResource() {
}

@Deprecated
protected static Map<String, String> getHttpHeaders(Request request, Options options) {
Map<String, String> headers = new HashMap<String, String>();

Expand All @@ -47,11 +49,13 @@ protected static Map<String, String> getHttpHeaders(Request request, Options opt
return headers;
}

protected static Map<String, String> getHttpHeadersV2(String uri, Request request, Options options) {
protected static Map<String, String> getHttpHeadersV2(String path, Request request, Options options) {
Map<String, String> headers = new HashMap<String, String>();

String randomString = UUID.randomUUID().toString();
headers.put(AUTHORIZATION, prepareAuthorizationStringV2(uri, request, randomString, options));
headers.put(AUTHORIZATION, prepareAuthorizationStringV2(path, request, randomString, options));
headers.put(RANDOM_HEADER_NAME, randomString);
headers.put(AUTHORIZATION_FALLBACK_HEADER, prepareAuthorizationString(request, randomString, options));

putClientVersionHeader(headers);
return headers;
Expand All @@ -75,8 +79,8 @@ private static String prepareAuthorizationString(Request request, String randomS
return IYZIWS_HEADER_NAME + options.getApiKey() + COLON + hash;
}

private static String prepareAuthorizationStringV2(String uri, Request request, String randomString, Options options) {
String authContent = IyziAuthV2Generator.generateAuthContent(uri, options.getApiKey(), options.getSecretKey(), randomString, request);
private static String prepareAuthorizationStringV2(String path, Request request, String randomString, Options options) {
String authContent = IyziAuthV2Generator.generateAuthContent(path, options.getApiKey(), options.getSecretKey(), randomString, request);
return IYZIWS_V2_HEADER_NAME + authContent;
}

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/iyzipay/ResponseSignatureGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.iyzipay;

import com.iyzipay.exception.HttpClientException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;

public interface ResponseSignatureGenerator {
String SEPARATOR = ":";
String HMAC_SHA_256 = "HmacSHA256";
String EMPTY_PARAM = "";

default String generateSignature(String secretKey, List<Object> params) {
try {
String dataToSign = appendSignatureParams(params);
Mac mac = Mac.getInstance(HMAC_SHA_256);
mac.init(new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), HMAC_SHA_256));
return DatatypeConverter.printHexBinary(mac.doFinal(dataToSign.getBytes(StandardCharsets.UTF_8))).toLowerCase(Locale.ENGLISH);
} catch (NoSuchAlgorithmException e) {
throw new HttpClientException("HMAC couldn't be generated", e);
} catch (InvalidKeyException e) {
throw new HttpClientException("Authentication content couldn't be generated", e);
}
}

default String appendSignatureParams(List<Object> signatureParameters) {
return signatureParameters.stream()
.map(this::convertParamToString)
.collect(Collectors.joining(SEPARATOR));
}

default String convertParamToString(Object parameter) {
if (Objects.isNull(parameter)) {
return EMPTY_PARAM;
} else if (parameter instanceof BigDecimal) {
return ((BigDecimal) parameter).stripTrailingZeros().toPlainString();
} else {
return parameter.toString();
}
}
}
29 changes: 24 additions & 5 deletions src/main/java/com/iyzipay/model/Apm.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
package com.iyzipay.model;

import com.iyzipay.HashValidator;
import com.iyzipay.HttpClient;
import com.iyzipay.Options;
import com.iyzipay.ResponseSignatureGenerator;
import com.iyzipay.request.CreateApmInitializeRequest;
import com.iyzipay.request.RetrieveApmRequest;

public class Apm extends ApmResource {
import java.util.Arrays;

public class Apm extends ApmResource implements ResponseSignatureGenerator {

public boolean verifySignatureForCreate(String secretKey) {
String calculated = generateSignature(secretKey, Arrays.asList(getPaymentId(), getRedirectUrl()));
return HashValidator.hashValid(getSignature(), calculated);
}

public static Apm create(CreateApmInitializeRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/apm/initialize",
String path = "/payment/apm/initialize";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
Apm.class);
}

public boolean verifySignatureForRetrieve(String secretKey) {
String calculated = generateSignature(secretKey,
Arrays.asList(getCurrency(), getBasketId(),
getConversationId(), getPaidPrice(),
getPrice(), getPaymentId(), getRedirectUrl()));
return HashValidator.hashValid(getSignature(), calculated);
}

public static Apm retrieve(RetrieveApmRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/apm/retrieve",
String path = "/payment/apm/retrieve";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
Apm.class);
}
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/com/iyzipay/model/ApmResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class ApmResource extends IyzipayResource {
private String apm;
private String mobilePhone;
private String paymentStatus;
private String signature;

public String getRedirectUrl() {
return redirectUrl;
Expand Down Expand Up @@ -219,6 +220,14 @@ public void setPaymentStatus(String paymentStatus) {
this.paymentStatus = paymentStatus;
}

public String getSignature() {
return signature;
}

public void setSignature(String signature) {
this.signature = signature;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/Approval.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ public class Approval extends IyzipayResource {
private String paymentTransactionId;

public static Approval create(CreateApprovalRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/iyzipos/item/approve",
String path = "/payment/iyzipos/item/approve";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
Approval.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicBkm.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ public class BasicBkm extends BasicPaymentResource {
private String paymentStatus;

public static BasicBkm retrieve(RetrieveBkmRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/bkm/auth/detail/basic",
String path = "/payment/bkm/auth/detail/basic";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicBkm.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicBkmInitialize.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ public class BasicBkmInitialize extends IyzipayResource {
private String token;

public static BasicBkmInitialize create(CreateBasicBkmInitializeRequest request, Options options) {
BasicBkmInitialize response = HttpClient.create().post(options.getBaseUrl() + "/payment/bkm/initialize/basic",
String path = "/payment/bkm/initialize/basic";
BasicBkmInitialize response = HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicBkmInitialize.class);
if (response != null) {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicPayment.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
public class BasicPayment extends BasicPaymentResource {

public static BasicPayment create(CreateBasicPaymentRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/auth/basic",
String path = "/payment/auth/basic";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicPayment.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicPaymentPostAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
public class BasicPaymentPostAuth extends BasicPaymentResource {

public static BasicPaymentPostAuth create(CreatePaymentPostAuthRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/postauth/basic",
String path = "/payment/postauth/basic";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicPaymentPostAuth.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicPaymentPreAuth.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
public class BasicPaymentPreAuth extends BasicPaymentResource {

public static BasicPaymentPreAuth create(CreateBasicPaymentRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/preauth/basic",
String path = "/payment/preauth/basic";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicPaymentPreAuth.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicThreedsInitialize.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ public class BasicThreedsInitialize extends IyzipayResource {
private String htmlContent;

public static BasicThreedsInitialize create(CreateBasicPaymentRequest request, Options options) {
BasicThreedsInitialize response = HttpClient.create().post(options.getBaseUrl() + "/payment/3dsecure/initialize/basic",
String path = "/payment/3dsecure/initialize/basic";
BasicThreedsInitialize response = HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicThreedsInitialize.class);
if (response != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ public class BasicThreedsInitializePreAuth extends IyzipayResource {
private String htmlContent;

public static BasicThreedsInitializePreAuth create(CreateBasicPaymentRequest request, Options options) {
BasicThreedsInitializePreAuth response = HttpClient.create().post(options.getBaseUrl() + "/payment/3dsecure/initialize/preauth/basic",
String path = "/payment/3dsecure/initialize/preauth/basic";
BasicThreedsInitializePreAuth response = HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicThreedsInitializePreAuth.class);
if (response != null) {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BasicThreedsPayment.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
public class BasicThreedsPayment extends BasicPaymentResource {

public static BasicThreedsPayment create(CreateThreedsPaymentRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/3dsecure/auth/basic",
String path = "/payment/3dsecure/auth/basic";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BasicThreedsPayment.class);
}
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/iyzipay/model/BinNumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ public class BinNumber extends IyzipayResource {
private Integer commercial;

public static BinNumber retrieve(RetrieveBinNumberRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/bin/check",
String path = "/payment/bin/check";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
BinNumber.class);
}
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/com/iyzipay/model/Bkm.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
package com.iyzipay.model;

import com.iyzipay.HashValidator;
import com.iyzipay.HttpClient;
import com.iyzipay.Options;
import com.iyzipay.ResponseSignatureGenerator;
import com.iyzipay.request.RetrieveBkmRequest;

public class Bkm extends PaymentResource {
import java.util.Arrays;

public class Bkm extends PaymentResource implements ResponseSignatureGenerator {

private String token;
private String callbackUrl;

public boolean verifySignature(String secretKey) {
String calculated = generateSignature(secretKey,
Arrays.asList(getPaymentId(), getPaymentStatus(),
getBasketId(), getConversationId(), getCurrency(),
getPaidPrice(), getPrice(), getToken()));
return HashValidator.hashValid(getSignature(), calculated);
}

public static Bkm retrieve(RetrieveBkmRequest request, Options options) {
return HttpClient.create().post(options.getBaseUrl() + "/payment/bkm/auth/detail",
String path = "/payment/bkm/auth/detail";
return HttpClient.create().post(options.getBaseUrl() + path,
getHttpProxy(options),
getHttpHeaders(request, options),
getHttpHeadersV2(path, request, options),
request,
Bkm.class);
}
Expand Down
Loading

0 comments on commit 60a73df

Please sign in to comment.