From 0a610a3df03fd3ee22d69698295b011e9f847fa6 Mon Sep 17 00:00:00 2001 From: ankitdas13 Date: Wed, 24 Aug 2022 18:03:42 +0530 Subject: [PATCH 1/4] security test --- src/main/java/com/razorpay/ApiClient.java | 290 +++++++++++------- src/main/java/com/razorpay/ApiUtils.java | 270 ++++++++-------- src/main/java/com/razorpay/Constants.java | 4 +- src/main/java/com/razorpay/Entity.java | 7 +- .../com/razorpay/EntityNameURLMapping.java | 27 +- src/main/java/com/razorpay/IAppUtils.java | 19 ++ .../java/com/razorpay/RazorpayClient.java | 75 +++-- .../java/com/razorpay/RazorpayException.java | 18 +- 8 files changed, 411 insertions(+), 299 deletions(-) create mode 100644 src/main/java/com/razorpay/IAppUtils.java diff --git a/src/main/java/com/razorpay/ApiClient.java b/src/main/java/com/razorpay/ApiClient.java index 319ec3c0..492b307b 100755 --- a/src/main/java/com/razorpay/ApiClient.java +++ b/src/main/java/com/razorpay/ApiClient.java @@ -1,22 +1,26 @@ package com.razorpay; -import java.io.IOException; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.Iterator; -import org.apache.commons.text.WordUtils; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; +import org.apache.commons.lang3.text.WordUtils; -import okhttp3.HttpUrl; -import okhttp3.Response; class ApiClient { String auth; + ApiUtils apiUtils; + private final String ENTITY = "entity"; private final String COLLECTION = "collection"; @@ -31,70 +35,142 @@ class ApiClient { private final int STATUS_MULTIPLE_CHOICE = 300; - ApiClient(String auth) { + ApiClient(String auth,ApiUtils apiUtils) { this.auth = auth; + this.apiUtils = apiUtils; } - public T get(String path, JSONObject requestObject) throws RazorpayException { - Response response = ApiUtils.getRequest(path, requestObject, auth); - return processResponse(response); + /** + * Create get request + * @param path + * @param requestObject + * @return + * @throws RazorpayException + * @throws IOException + * @throws URISyntaxException + * @throws JSONException + */ + public T get(String path, JSONObject requestObject) throws RazorpayException, IOException, URISyntaxException, JSONException { + + String query = null; + if(requestObject != null){ + query = queryBuilder(requestObject); + } + URL builder = getBuilder(path,query); + String request = requestObject==null ? null : requestObject.toString(); + String response = apiUtils.processGetRequest(builder.toString(),request, auth); + return processResponse(response,builder.toString()); } - public T post(String path, JSONObject requestObject) throws RazorpayException { - Response response = ApiUtils.postRequest(path, requestObject, auth); - return processResponse(response); + /** + * Create post request + * @param path + * @param requestObject + * @return + * @throws RazorpayException + * @throws IOException + * @throws URISyntaxException + * @throws JSONException + */ + public T post(String path, JSONObject requestObject) throws RazorpayException, IOException, URISyntaxException, JSONException { + URL builder = getBuilder(path,null); + String request = requestObject==null ? null : requestObject.toString(); + String response = apiUtils.processPostRequest(builder.toString(),request, auth); + return processResponse(response,builder.toString()); } - public T put(String path, JSONObject requestObject) throws RazorpayException { - Response response = ApiUtils.putRequest(path, requestObject, auth); - return processResponse(response); + /** + * Create put request + * @param path + * @param requestObject + * @return + * @throws RazorpayException + * @throws IOException + * @throws URISyntaxException + * @throws JSONException + */ + public T put(String path, JSONObject requestObject) throws RazorpayException, JSONException, IOException, URISyntaxException { + URL builder = getBuilder(path,null); + String response = apiUtils.processPutRequest(builder.toString(),requestObject.toString(), auth); + return processResponse(response,builder.toString()); } - public T patch(String path, JSONObject requestObject) throws RazorpayException { - Response response = ApiUtils.patchRequest(path, requestObject, auth); - return processResponse(response); + /** + * Create patch request + * @param path + * @param requestObject + * @return + * @throws RazorpayException + * @throws IOException + * @throws URISyntaxException + * @throws JSONException + */ + public T patch(String path, JSONObject requestObject) throws RazorpayException, IOException, URISyntaxException, JSONException { + URL builder = getBuilder(path,null); + String response = apiUtils.processPatchRequest(builder.toString(),requestObject.toString(), auth); + return processResponse(response,builder.toString()); } + /** + * Create delete request + * @param path + * @param requestObject + * @param + * @return + * @throws RazorpayException + * @throws IOException + * @throws URISyntaxException + * @throws JSONException + */ + public T delete(String path, JSONObject requestObject) throws RazorpayException, IOException, URISyntaxException, JSONException { + URL builder = getBuilder(path,null); + String request = requestObject==null ? null : requestObject.toString(); + String response = apiUtils.processDeleteRequest(builder.toString(),request, auth); + return processDeleteResponse(response,builder.toString()); + } ArrayList getCollection(String path, JSONObject requestObject) - throws RazorpayException { - Response response = ApiUtils.getRequest(path, requestObject, auth); - return processCollectionResponse(response); + throws RazorpayException, IOException, URISyntaxException, JSONException { + String query = null; + if(requestObject != null){ + query = queryBuilder(requestObject); + } + URL builder = getBuilder(path,query); + String response = apiUtils.processGetRequest(builder.toString(),null, auth); + return processCollectionResponse(response,builder.toString()); } - public T delete(String path, JSONObject requestObject) throws RazorpayException { - Response response = ApiUtils.deleteRequest(path, requestObject, auth); - return processDeleteResponse(response); + ArrayList postCollection(String path, JSONObject requestObject) throws RazorpayException, IOException, URISyntaxException, JSONException { + URL builder = getBuilder(path,null); + String response = apiUtils.processPostRequest(builder.toString(),requestObject.toString(), auth); + return processCollectionResponse(response,builder.toString()); } - private T processDeleteResponse(Response response) throws RazorpayException { - if (response == null) { - throw new RazorpayException("Invalid Response from server"); - } - int statusCode = response.code(); - String responseBody = null; - JSONObject responseJson = null; + private ArrayList parseCollectionResponse(JSONArray jsonArray, URL requestUrl) + throws RazorpayException, JSONException { + ArrayList modelList = new ArrayList(); try { - responseBody = response.body().string(); - if(responseBody.equals("[]")){ - return (T) Collections.emptyList(); - } - else if(response.code()==204){ - return null; - } - else{ - responseJson = new JSONObject(responseBody); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObj = jsonArray.getJSONObject(i); + T t = parseResponse(jsonObj, getEntity(jsonObj,requestUrl)); + modelList.add(t); } - } catch (IOException e) { - throw new RazorpayException(e.getMessage()); + return modelList; + } catch (RazorpayException e) { + throw e; } + } - if (statusCode < STATUS_OK || statusCode >= STATUS_MULTIPLE_CHOICE) { - throwException(statusCode, responseJson); + T processResponse(String response,String url) throws RazorpayException, JSONException, IOException { + if (response == null) { + throw new RazorpayException("Invalid Response from server"); } - return (T) parseResponse(responseJson, getEntity(responseJson, response.request().url())); + + JSONObject responseJson = new JSONObject(response); + return parseResponse(responseJson, getEntity(responseJson, new URL(url))); + } private T parseResponse(JSONObject jsonObject, String entity) throws RazorpayException { @@ -106,89 +182,49 @@ private T parseResponse(JSONObject jsonObject, String entity) throw new RazorpayException("Unable to parse response because of " + e.getMessage()); } } - throw new RazorpayException("Unable to parse response"); } - private ArrayList parseCollectionResponse(JSONArray jsonArray, HttpUrl requestUrl) - throws RazorpayException { - - ArrayList modelList = new ArrayList(); - try { - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject jsonObj = jsonArray.getJSONObject(i); - T t = parseResponse(jsonObj, getEntity(jsonObj,requestUrl)); - modelList.add(t); - } - return modelList; - } catch (RazorpayException e) { - throw e; - } - } - - /* - * this method will take http url as : https://api.razorpay.com/v1/invocies - * and will return entity name with the help of @EntityNameURLMapping class - */ - private String getEntityNameFromURL(HttpUrl url) { - String param = url.pathSegments().get(1); - return EntityNameURLMapping.getEntityName(param); - } - - - T processResponse(Response response) throws RazorpayException { + ArrayList processCollectionResponse(String response,String url) + throws RazorpayException, JSONException, IOException { if (response == null) { throw new RazorpayException("Invalid Response from server"); } - - int statusCode = response.code(); - String responseBody = null; - JSONObject responseJson = null; - try { - responseBody = response.body().string(); - responseJson = new JSONObject(responseBody); - } catch (IOException e) { - throw new RazorpayException(e.getMessage()); - } - - if (statusCode >= STATUS_OK && statusCode < STATUS_MULTIPLE_CHOICE) { - return parseResponse(responseJson, getEntity(responseJson, response.request().url())); - } - - throwException(statusCode, responseJson); - return null; + String collectionName = null; + JSONObject responseJson = new JSONObject(response); + collectionName = responseJson.has("payment_links")? "payment_links": "items"; + return parseCollectionResponse(responseJson.getJSONArray(collectionName), new URL(url)); } - ArrayList processCollectionResponse(Response response) - throws RazorpayException { + private T processDeleteResponse(String response,String url) throws RazorpayException, JSONException, IOException { if (response == null) { throw new RazorpayException("Invalid Response from server"); } - - int statusCode = response.code(); - String responseBody = null; JSONObject responseJson = null; - - try { - responseBody = response.body().string(); - responseJson = new JSONObject(responseBody); - } catch (IOException e) { - throw new RazorpayException(e.getMessage()); + if(response.startsWith("[")){ + return (T) Collections.emptyList(); } - - String collectionName = null; - collectionName = responseJson.has("payment_links")? - "payment_links": "items"; - - if (statusCode >= STATUS_OK && statusCode < STATUS_MULTIPLE_CHOICE) { - return parseCollectionResponse(responseJson.getJSONArray(collectionName), response.request().url()); + else if(response.length()==0){ + return null; + } + else{ + responseJson = new JSONObject(response); } - throwException(statusCode, responseJson); - return null; + return (T) parseResponse(responseJson, getEntity(responseJson, new URL(url))); + } + + /* + * this method will take http url as : https://api.razorpay.com/v1/invocies + * and will return entity name with the help of @EntityNameURLMapping class + */ + private String getEntityNameFromURL(URL url) { + String[] path = url.getPath().split("/"); + String param = path[2]; + return EntityNameURLMapping.getEntityName(param); } - private String getEntity(JSONObject jsonObj, HttpUrl url) { + private String getEntity(JSONObject jsonObj, URL url) throws JSONException { if(!jsonObj.has(ENTITY)) { return getEntityNameFromURL(url); }else if(jsonObj.get("entity").toString().equals("settlement.ondemand")){ @@ -198,7 +234,34 @@ private String getEntity(JSONObject jsonObj, HttpUrl url) { } } - private void throwException(int statusCode, JSONObject responseJson) throws RazorpayException { + private String queryBuilder(JSONObject requestObject) throws JSONException { + String query = null; + Iterator keys = requestObject.keys(); + while(keys.hasNext()) { + String key = keys.next(); + if(query==null){ + query = ""; + } + query += "&" + key + "=" + requestObject.get(key); + } + + return query; + } + + /** + * The API url is built using this method + * @param path + * @param query + * @return + * @throws URISyntaxException + * @throws MalformedURLException + */ + public static URL getBuilder(String path,String query) throws URISyntaxException, MalformedURLException { + URI uri = new URI(Constants.SCHEME, Constants.HOSTNAME, "/"+Constants.VERSION + "/"+path+"", query,null); + return uri.toURL(); + } + + private void throwException(int statusCode, JSONObject responseJson) throws RazorpayException, JSONException { if (responseJson.has(ERROR)) { JSONObject errorResponse = responseJson.getJSONObject(ERROR); String code = errorResponse.getString(STATUS_CODE); @@ -217,6 +280,7 @@ private void throwServerException(int statusCode, String responseBody) throws Ra private Class getClass(String entity) { try { + String CapEntity = entity.substring(0, 1).toUpperCase() + entity.substring(1); String entityClass = "com.razorpay." + WordUtils.capitalize(entity, '_').replaceAll("_", ""); return Class.forName(entityClass); } catch (ClassNotFoundException e) { diff --git a/src/main/java/com/razorpay/ApiUtils.java b/src/main/java/com/razorpay/ApiUtils.java index 0dcc73da..ab1ffeec 100755 --- a/src/main/java/com/razorpay/ApiUtils.java +++ b/src/main/java/com/razorpay/ApiUtils.java @@ -1,179 +1,197 @@ package com.razorpay; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; + +import java.io.*; +import java.net.*; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import org.json.JSONObject; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.logging.HttpLoggingInterceptor; +import javax.net.ssl.HttpsURLConnection; -class ApiUtils { - private static OkHttpClient client; +class ApiUtils implements IAppUtils { private static Map headers = new HashMap(); private static String version = null; - static void createHttpClientInstance(boolean enableLogging) throws RazorpayException { - if (client == null) { - HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); - if (enableLogging) { - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC); - } else { - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); - } - - try { - client = new OkHttpClient.Builder() - .readTimeout(60, TimeUnit.SECONDS) - .writeTimeout(60, TimeUnit.SECONDS) - .addInterceptor(loggingInterceptor) - .sslSocketFactory(new CustomTLSSocketFactory(), createDefaultTrustManager()) - .build(); - } catch (Exception e) { - throw new RazorpayException(e); - } - } - - Properties properties = new Properties(); - try { - properties.load(ApiUtils.class.getResourceAsStream("/project.properties")); - version = (String) properties.get("version"); - } catch (IOException e) { - throw new RazorpayException(e.getMessage()); - } - } - private enum Method { GET, POST, PUT, PATCH, DELETE } - static Response postRequest(String path, JSONObject requestObject, String auth) - throws RazorpayException { - HttpUrl.Builder builder = getBuilder(path); + @Override + public String processGetRequest(String path, String requestObject, String auth) throws RazorpayException, IOException, URISyntaxException { + HttpsURLConnection httpconn = createRequest(Method.GET.name(), new URL(path), null, auth); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + httpconn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { - String requestContent = requestObject == null ? "" : requestObject.toString(); - RequestBody requestBody = RequestBody.create(Constants.MEDIA_TYPE_JSON, requestContent); + sb.append(line + "\n"); + } + br.close(); - Request request = - createRequest(Method.POST.name(), builder.build().toString(), requestBody, auth); - return processRequest(request); + return sb.toString(); + } catch (IOException e) { + InputStream errorStream = httpconn.getErrorStream(); + String getMessage = HttpException(errorStream); + throw new RazorpayException(getMessage); + } } - static Response putRequest(String path, JSONObject requestObject, String auth) - throws RazorpayException { + @Override + public String processPostRequest(String path, String requestObject, String auth) throws RazorpayException, IOException, URISyntaxException { - HttpUrl.Builder builder = getBuilder(path); + HttpsURLConnection httpconn = createRequest(Method.POST.name(), new URL(path), requestObject, auth); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + httpconn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { - String requestContent = requestObject == null ? "" : requestObject.toString(); - RequestBody requestBody = RequestBody.create(Constants.MEDIA_TYPE_JSON, requestContent); + sb.append(line + "\n"); + } + br.close(); - Request request = - createRequest(Method.PUT.name(), builder.build().toString(), requestBody, auth); - return processRequest(request); + return sb.toString(); + } catch (IOException e) { + InputStream errorStream = httpconn.getErrorStream(); + String getMessage = HttpException(errorStream); + throw new RazorpayException(getMessage); + } } - static Response patchRequest(String path, JSONObject requestObject, String auth) - throws RazorpayException { + @Override + public String processDeleteRequest(String path, String requestObject, String auth) throws RazorpayException, IOException, URISyntaxException { - HttpUrl.Builder builder = getBuilder(path); + HttpsURLConnection httpconn = createRequest(Method.DELETE.name(), new URL(path), requestObject, auth); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + httpconn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { - String requestContent = requestObject == null ? "" : requestObject.toString(); - RequestBody requestBody = RequestBody.create(Constants.MEDIA_TYPE_JSON, requestContent); + sb.append(line + "\n"); + } + br.close(); - Request request = - createRequest(Method.PATCH.name(), builder.build().toString(), requestBody, auth); - return processRequest(request); + return sb.toString(); + } catch (IOException e) { + InputStream errorStream = httpconn.getErrorStream(); + String getMessage = HttpException(errorStream); + throw new RazorpayException(getMessage); + } } - static Response getRequest(String path, JSONObject requestObject, String auth) - throws RazorpayException { + @Override + public String processPutRequest(String path, String requestObject, String auth) throws RazorpayException, IOException, URISyntaxException { - HttpUrl.Builder builder = getBuilder(path); - addQueryParams(builder, requestObject); + HttpsURLConnection httpconn = createRequest(Method.PUT.name(), new URL(path), requestObject, auth); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + httpconn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + + sb.append(line + "\n"); + } + br.close(); - Request request = createRequest(Method.GET.name(), builder.build().toString(), null, auth); - return processRequest(request); + return sb.toString(); + } catch (IOException e) { + InputStream errorStream = httpconn.getErrorStream(); + String getMessage = HttpException(errorStream); + throw new RazorpayException(getMessage); + } } - static Response deleteRequest(String path, JSONObject requestObject, String auth) - throws RazorpayException { + @Override + public String processPatchRequest(String path, String requestObject, String auth) throws RazorpayException, IOException, URISyntaxException { - HttpUrl.Builder builder = getBuilder(path); - addQueryParams(builder, requestObject); + HttpsURLConnection httpconn = createRequest(Method.PATCH.name(), new URL(path), requestObject, auth); + try { + BufferedReader br = new BufferedReader(new InputStreamReader( + httpconn.getInputStream())); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { - Request request = createRequest(Method.DELETE.name(), builder.build().toString(), null, auth); - return processRequest(request); - } + sb.append(line + "\n"); + } + br.close(); - private static HttpUrl.Builder getBuilder(String path) { - return new HttpUrl.Builder().scheme(Constants.SCHEME).host(Constants.HOSTNAME) - .port(Constants.PORT).addPathSegment(Constants.VERSION).addPathSegments(path); + return sb.toString(); + } catch (IOException e) { + InputStream errorStream = httpconn.getErrorStream(); + String getMessage = HttpException(errorStream); + throw new RazorpayException(getMessage); + } } - private static Request createRequest(String method, String url, RequestBody requestBody, - String auth) { - Request.Builder builder = - new Request.Builder().url(url).addHeader(Constants.AUTH_HEADER_KEY, auth); - builder.addHeader(Constants.USER_AGENT, - "Razorpay/v1 JAVASDK/" + version + " Java/" + System.getProperty("java.version")); - - for (Map.Entry header : headers.entrySet()) { - builder.addHeader(header.getKey(), header.getValue()); + private static HttpsURLConnection createRequest(String method, URL url, String requestBody, + String auth) throws IOException { + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setConnectTimeout(60*1000); + conn.setReadTimeout(60*1000); + conn.setSSLSocketFactory(new TLSSocketConnectionFactory()); + /* Checking headers value */ + if(headers.size() > 0){ + for(Map.Entry header: headers.entrySet()){ + conn.setRequestProperty(header.getKey(), header.getValue()); + } } - return builder.method(method, requestBody).build(); - } - - private static void addQueryParams(HttpUrl.Builder builder, JSONObject request) { - if (request == null) - return; + conn.setRequestProperty("Authorization", "Basic " + auth); + conn.setRequestProperty(Constants.USER_AGENT, "Razorpay/v1 JAVASDK/" + version + " Java/" + System.getProperty("java.version")); - Iterator keys = request.keys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - builder.addQueryParameter(key, request.get(key).toString()); + if (method == Method.PATCH.name()) { + conn.setRequestMethod("POST"); + conn.setRequestProperty("X-HTTP-Method-Override", "PATCH"); + }else{ + conn.setRequestMethod(method); } - } - private static Response processRequest(Request request) throws RazorpayException { - try { - return client.newCall(request).execute(); - } catch (IOException e) { - throw new RazorpayException(e.getMessage()); + conn.setUseCaches(false); + if (conn.getRequestMethod() == Method.POST.name() || conn.getRequestMethod() == Method.PUT.name()) { + conn.setRequestProperty("Content-Type", "application/json"); + if(requestBody != null ) { + byte[] out = requestBody.getBytes("UTF-8"); + conn.setDoOutput(true); + OutputStream stream = conn.getOutputStream(); + stream.write(out); + } } + + return conn; } static void addHeaders(Map header) { headers.putAll(header); } - - private static X509TrustManager createDefaultTrustManager() throws NoSuchAlgorithmException, KeyStoreException { - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { - throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); + + private static String HttpException(InputStream errorStream) throws IOException { + String responseString = null; + BufferedInputStream bis = null; + try { + StringBuilder sb = new StringBuilder(); + bis = new BufferedInputStream(errorStream); + byte[] byteContents = new byte[4096]; + int bytesRead; + String strContents; + while ((bytesRead = bis.read(byteContents)) != -1) { + strContents = new String(byteContents, 0, bytesRead, "UTF-8"); // You might need to replace the charSet as per the responseEncoding returned by httpurlconnection above + sb.append(strContents); + } + return sb.toString(); + } finally { + if (bis != null) { + bis.close(); + } } - X509TrustManager trustManager = (X509TrustManager) trustManagers[0]; - return trustManager; } } diff --git a/src/main/java/com/razorpay/Constants.java b/src/main/java/com/razorpay/Constants.java index 748d58db..57716dbd 100755 --- a/src/main/java/com/razorpay/Constants.java +++ b/src/main/java/com/razorpay/Constants.java @@ -1,6 +1,5 @@ package com.razorpay; -import okhttp3.MediaType; public class Constants { @@ -12,7 +11,6 @@ public class Constants { static final String AUTH_HEADER_KEY = "Authorization"; static final String USER_AGENT = "User-Agent"; - static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8"); // API URI static final String PAYMENT_GET = "payments/%s"; @@ -133,4 +131,4 @@ public class Constants { static final String VIRTUAL_ACCOUNT_RECEIVERS = "virtual_accounts/%s/receivers"; static final String VIRTUAL_ACCOUNT_ALLOWEDPAYERS = "virtual_accounts/%s/allowed_payers"; static final String VIRTUAL_ACCOUNT_DELETE_ALLOWEDPAYERS = "virtual_accounts/%s/allowed_payers/%s"; -} +} \ No newline at end of file diff --git a/src/main/java/com/razorpay/Entity.java b/src/main/java/com/razorpay/Entity.java index ec46e474..c2623452 100644 --- a/src/main/java/com/razorpay/Entity.java +++ b/src/main/java/com/razorpay/Entity.java @@ -2,6 +2,7 @@ import java.util.Date; +import org.json.JSONException; import org.json.JSONObject; public abstract class Entity { @@ -15,7 +16,7 @@ public abstract class Entity { this.modelJson = jsonObject; } - public T get(String key) { + public T get(String key) throws JSONException { // Return null if key not in JSONObject if (!has(key)) { return null; @@ -34,7 +35,7 @@ public T get(String key) { public JSONObject toJson() { return modelJson; } - + public boolean has(String key) { return modelJson.has(key); } @@ -42,4 +43,4 @@ public boolean has(String key) { public String toString() { return modelJson.toString(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/razorpay/EntityNameURLMapping.java b/src/main/java/com/razorpay/EntityNameURLMapping.java index 106f4885..e00af681 100644 --- a/src/main/java/com/razorpay/EntityNameURLMapping.java +++ b/src/main/java/com/razorpay/EntityNameURLMapping.java @@ -1,19 +1,19 @@ package com.razorpay; -import java.util.Arrays; +import java.util.*; - /** +/** * Enum name is acting as url and entity is denoting Entity class - * ex: https://api.razorpay.com/v1/invocies - * getEntityName method will take "invoices" from above mentioned url - * and will return "invoice" as entity name as mentioned below in mapping INVOICES("invoice") + * ex: https://api.razorpay.com/v1/invoices + * getEntityName method will take "invoices" from above mentioned url + * and will return "invoice" as entity name as mentioned below in mapping INVOICES("invoice") */ public enum EntityNameURLMapping { - + INVOICES("invoice"), SETTLEMENTS("settlement"), - PAYMENTS("payment"), + PAYMENTS("payment"), PAYMENT_LINKS("payment_link"), ITEMS("item"), CUSTOMERS("customer"); @@ -23,15 +23,20 @@ public enum EntityNameURLMapping { EntityNameURLMapping(String entity) { this.entity= entity; } - + private String getEntity() { return entity; } - public static String getEntityName(String urlStirng) + public static String getEntityName(String urlString) { - EntityNameURLMapping item = Arrays.asList(values()).stream().filter( val -> val.name().equalsIgnoreCase(urlStirng)).findFirst().orElseThrow(() -> new IllegalArgumentException("Unable to resolve")); - return item.getEntity(); + EntityNameURLMapping entityNames[] = EntityNameURLMapping.values(); + for(EntityNameURLMapping entityName : entityNames){ + if(urlString.equals(entityName.toString().toLowerCase())){ + return entityName.entity; + } + } + throw new IllegalArgumentException("Unable to resolve"); } } \ No newline at end of file diff --git a/src/main/java/com/razorpay/IAppUtils.java b/src/main/java/com/razorpay/IAppUtils.java new file mode 100644 index 00000000..99c087f6 --- /dev/null +++ b/src/main/java/com/razorpay/IAppUtils.java @@ -0,0 +1,19 @@ +package com.razorpay; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.URISyntaxException; + +interface IAppUtils { + + String processGetRequest(String path, String request, String auth) throws RazorpayException, IOException, URISyntaxException; + + String processPostRequest(String path, String request, String auth) throws RazorpayException, IOException, URISyntaxException; + String processDeleteRequest(String path, String request, String auth) throws RazorpayException, IOException, URISyntaxException; + + String processPatchRequest(String path, String request, String auth) throws RazorpayException, IOException, URISyntaxException; + + String processPutRequest(String path, String request, String auth) throws RazorpayException, IOException, URISyntaxException; +} \ No newline at end of file diff --git a/src/main/java/com/razorpay/RazorpayClient.java b/src/main/java/com/razorpay/RazorpayClient.java index a42bbcdd..b72bfae0 100755 --- a/src/main/java/com/razorpay/RazorpayClient.java +++ b/src/main/java/com/razorpay/RazorpayClient.java @@ -1,55 +1,74 @@ package com.razorpay; + +import java.io.UnsupportedEncodingException; import java.util.Map; -import okhttp3.Credentials; public class RazorpayClient { public PaymentClient payments; - public RefundClient refunds; - public OrderClient orders; public InvoiceClient invoices; - public CardClient cards; public CustomerClient customers; + public CardClient cards; + public FundAccountClient fundAccount; + public ItemClient items; + public OrderClient orders; + public AddonClient addons; + public RefundClient refunds; public TransferClient transfers; + public SubscriptionRegistrationClient subscriptionRegistrations; public SubscriptionClient subscriptions; - public AddonClient addons; public PlanClient plans; public SettlementClient settlement; public QrCodeClient qrCode; public PaymentLinkClient paymentLink; - public ItemClient items; - public FundAccountClient fundAccount; public VirtualAccountClient virtualAccounts; - public RazorpayClient(String key, String secret) throws RazorpayException { + public RazorpayClient(String key, String secret) throws RazorpayException, UnsupportedEncodingException { this(key, secret, false); } - public RazorpayClient(String key, String secret, Boolean enableLogging) throws RazorpayException { - ApiUtils.createHttpClientInstance(enableLogging); - String auth = Credentials.basic(key, secret); - payments = new PaymentClient(auth); - refunds = new RefundClient(auth); - orders = new OrderClient(auth); - invoices = new InvoiceClient(auth); - cards = new CardClient(auth); - customers = new CustomerClient(auth); - transfers = new TransferClient(auth); - subscriptions = new SubscriptionClient(auth); - addons = new AddonClient(auth); - plans = new PlanClient(auth); - settlement = new SettlementClient(auth); - qrCode = new QrCodeClient(auth); - paymentLink = new PaymentLinkClient(auth); - items = new ItemClient(auth); - fundAccount = new FundAccountClient(auth); - virtualAccounts = new VirtualAccountClient(auth); + /** + * Initializes Razorpay client instance + * @param key + * @param secret + * @param enableLogging + * @throws RazorpayException + * @throws UnsupportedEncodingException + */ + public RazorpayClient(String key, String secret, Boolean enableLogging) throws RazorpayException, UnsupportedEncodingException { + byte[] message = (key + ":" + secret).getBytes("UTF-8"); + String auth = javax.xml.bind.DatatypeConverter.printBase64Binary(message); + ApiUtils apiUtils = new ApiUtils(); + + cards = new CardClient(auth,apiUtils); + items = new ItemClient(auth,apiUtils); + plans = new PlanClient(auth,apiUtils); + orders = new OrderClient(auth,apiUtils); + addons = new AddonClient(auth,apiUtils); + qrCode = new QrCodeClient(auth,apiUtils); + refunds = new RefundClient(auth,apiUtils); + payments = new PaymentClient(auth,apiUtils); + invoices = new InvoiceClient(auth,apiUtils); + customers = new CustomerClient(auth,apiUtils); + transfers = new TransferClient(auth,apiUtils); + settlement = new SettlementClient(auth,apiUtils); + fundAccount = new FundAccountClient(auth,apiUtils); + paymentLink = new PaymentLinkClient(auth,apiUtils); + subscriptions = new SubscriptionClient(auth,apiUtils); + virtualAccounts = new VirtualAccountClient(auth,apiUtils); + subscriptionRegistrations = new SubscriptionRegistrationClient(auth,apiUtils); } + /** + * Add headers + * ex: X-Razorpay-Account + * @param headers + * @return + */ public RazorpayClient addHeaders(Map headers) { ApiUtils.addHeaders(headers); return this; } -} +} \ No newline at end of file diff --git a/src/main/java/com/razorpay/RazorpayException.java b/src/main/java/com/razorpay/RazorpayException.java index f89c7f45..f4e2986f 100644 --- a/src/main/java/com/razorpay/RazorpayException.java +++ b/src/main/java/com/razorpay/RazorpayException.java @@ -1,21 +1,9 @@ package com.razorpay; -public class RazorpayException extends Exception { + +public class RazorpayException extends Exception { public RazorpayException(String message) { super(message); } - - public RazorpayException(String message, Throwable cause) { - super(message, cause); - } - - public RazorpayException(Throwable cause) { - super(cause); - } - - public RazorpayException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} +} \ No newline at end of file From a874ad88a74a2eb2aacc223cacd8f7f70165739a Mon Sep 17 00:00:00 2001 From: ankitdas13 Date: Wed, 24 Aug 2022 18:06:30 +0530 Subject: [PATCH 2/4] update pom --- pom.xml | 101 +++++++++++++++++--------------------------------------- 1 file changed, 30 insertions(+), 71 deletions(-) diff --git a/pom.xml b/pom.xml index 1b0abe6f..78bd2e50 100644 --- a/pom.xml +++ b/pom.xml @@ -1,16 +1,13 @@ 4.0.0 - com.razorpay razorpay-java - 1.4.3 + 1.1.1 jar - razorpay-java Official java bindings for the Razorpay API https://github.com/razorpay/razorpay-java - Razorpay @@ -19,13 +16,11 @@ https://www.razorpay.com - scm:git:git@github.com:razorpay/razorpay-java.git scm:git:git@github.com:razorpay/razorpay-java.git git@github.com:razorpay/razorpay-java.git - MIT License @@ -33,80 +28,40 @@ repo - UTF-8 - 1.8 - 1.8 + 6 + 6 - - - - - junit - junit - 4.13.2 - test - - - - - org.mockito - mockito-inline - 2.13.0 - test - - org.json json - test - - - - com.fasterxml.jackson.core - jackson-databind - 2.13.1 - test - - - - - - - - com.squareup.okhttp3 - okhttp - 3.10.0 + 20070829 - - com.squareup.okhttp3 - logging-interceptor - 3.10.0 + org.apache.commons + commons-lang3 + 3.1 - - org.json - json - 20180130 + junit + junit + 4.10 + test - - commons-codec - commons-codec - 1.11 + org.mockito + mockito-all + 1.10.19 + test - - org.apache.commons - commons-text - 1.3 + org.bouncycastle + bcprov-jdk15on + 1.54 - - ossrh @@ -117,21 +72,18 @@ https://oss.sonatype.org/service/local/repositories/releases/content/ - - src/main/resources true - org.sonatype.plugins nexus-staging-maven-plugin - 1.6.9 + 1.6.4 true ossrh @@ -139,10 +91,19 @@ true + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.6 + 1.6 + + org.apache.maven.plugins maven-source-plugin - 3.0.1 + 2.3 attach-sources @@ -155,7 +116,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.1 + 2.9.1 attach-javadocs @@ -180,7 +141,5 @@ - - \ No newline at end of file From 938397a60bf10abad1bc398c09974d9a20f50ddc Mon Sep 17 00:00:00 2001 From: ankitdas13 Date: Wed, 24 Aug 2022 18:08:57 +0530 Subject: [PATCH 3/4] added tlsconnectionfactory --- .../razorpay/TLSSocketConnectionFactory.java | 372 ++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 src/main/java/com/razorpay/TLSSocketConnectionFactory.java diff --git a/src/main/java/com/razorpay/TLSSocketConnectionFactory.java b/src/main/java/com/razorpay/TLSSocketConnectionFactory.java new file mode 100644 index 00000000..9574fd2b --- /dev/null +++ b/src/main/java/com/razorpay/TLSSocketConnectionFactory.java @@ -0,0 +1,372 @@ +package com.razorpay; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.Principal; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.security.cert.X509Certificate; + +import org.bouncycastle.crypto.tls.Certificate; +import org.bouncycastle.crypto.tls.CertificateRequest; +import org.bouncycastle.crypto.tls.DefaultTlsClient; +import org.bouncycastle.crypto.tls.ExtensionType; +import org.bouncycastle.crypto.tls.TlsAuthentication; +import org.bouncycastle.crypto.tls.TlsClientProtocol; +import org.bouncycastle.crypto.tls.TlsCredentials; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +/** + * This Class enables TLS V1.2 connection based on BouncyCastle Providers. Just + * to use: URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2); + * HttpsURLConnection con = (HttpsURLConnection )myurl.openConnection(); + * con.setSSLSocketFactory(new TSLSocketConnectionFactory()); + * + * @author AZIMUTS + * + */ +public class TLSSocketConnectionFactory extends SSLSocketFactory { + + // ******************Adding Custom BouncyCastleProvider*********************// + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + // ******************HANDSHAKE LISTENER*********************// + public class TLSHandshakeListener implements HandshakeCompletedListener { + + @Override + public void handshakeCompleted(HandshakeCompletedEvent event) { + + } + } + + private SecureRandom _secureRandom = new SecureRandom(); + + // ******************Adding Custom BouncyCastleProvider*********************// + @Override + public Socket createSocket(Socket socket, final String host, int port, boolean arg3) throws IOException { + if (socket == null) { + socket = new Socket(); + } + if (!socket.isConnected()) { + socket.connect(new InetSocketAddress(host, port)); + } + + final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom); + return _createSSLSocket(host, tlsClientProtocol); + } + + // ******************SOCKET FACTORY METHODS*********************// + @Override + public String[] getDefaultCipherSuites() { + return null; + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return null; + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return null; + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return null; + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return null; + } + + // ******************SOCKET CREATION*********************// + private SSLSocket _createSSLSocket(final String host, final TlsClientProtocol tlsClientProtocol) { + return new SSLSocket() { + private java.security.cert.Certificate[] peertCerts; + + @Override + public InputStream getInputStream() throws IOException { + return tlsClientProtocol.getInputStream(); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return tlsClientProtocol.getOutputStream(); + } + + @Override + public synchronized void close() throws IOException { + tlsClientProtocol.close(); + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) { + + } + + @Override + public boolean getEnableSessionCreation() { + return false; + } + + @Override + public String[] getEnabledCipherSuites() { + return null; + } + + @Override + public String[] getEnabledProtocols() { + return null; + } + + @Override + public boolean getNeedClientAuth() { + return false; + } + + @Override + public SSLSession getSession() { + return new SSLSession() { + + @Override + public int getApplicationBufferSize() { + return 0; + } + + @Override + public String getCipherSuite() { + throw new UnsupportedOperationException(); + } + + @Override + public long getCreationTime() { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] getId() { + throw new UnsupportedOperationException(); + } + + @Override + public long getLastAccessedTime() { + throw new UnsupportedOperationException(); + } + + @Override + public java.security.cert.Certificate[] getLocalCertificates() { + throw new UnsupportedOperationException(); + } + + @Override + public Principal getLocalPrincipal() { + throw new UnsupportedOperationException(); + } + + @Override + public int getPacketBufferSize() { + throw new UnsupportedOperationException(); + } + + @Override + public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { + return null; + } + + @Override + public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { + return peertCerts; + } + + @Override + public String getPeerHost() { + throw new UnsupportedOperationException(); + } + + @Override + public int getPeerPort() { + return 0; + } + + @Override + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { + return null; + //throw new UnsupportedOperationException(); + } + + @Override + public String getProtocol() { + throw new UnsupportedOperationException(); + } + + @Override + public SSLSessionContext getSessionContext() { + throw new UnsupportedOperationException(); + } + + @Override + public Object getValue(String arg0) { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getValueNames() { + throw new UnsupportedOperationException(); + } + + @Override + public void invalidate() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isValid() { + throw new UnsupportedOperationException(); + } + + @Override + public void putValue(String arg0, Object arg1) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeValue(String arg0) { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public String[] getSupportedProtocols() { + return null; + } + + @Override + public boolean getUseClientMode() { + return false; + } + + @Override + public boolean getWantClientAuth() { + return false; + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) { + } + + @Override + public void setEnableSessionCreation(boolean arg0) { + } + + @Override + public void setEnabledCipherSuites(String[] arg0) { + } + + @Override + public void setEnabledProtocols(String[] arg0) { + } + + @Override + public void setNeedClientAuth(boolean arg0) { + } + + @Override + public void setUseClientMode(boolean arg0) { + } + + @Override + public void setWantClientAuth(boolean arg0) { + } + + @Override + public String[] getSupportedCipherSuites() { + return null; + } + + @Override + public void startHandshake() throws IOException { + tlsClientProtocol.connect(new DefaultTlsClient() { + @Override + public Hashtable getClientExtensions() throws IOException { + Hashtable clientExtensions = super.getClientExtensions(); + if (clientExtensions == null) { + clientExtensions = new Hashtable(); + } + + //Add host_name + byte[] host_name = host.getBytes(); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final DataOutputStream dos = new DataOutputStream(baos); + dos.writeShort(host_name.length + 3); // entry size + dos.writeByte(0); // name type = hostname + dos.writeShort(host_name.length); + dos.write(host_name); + dos.close(); + clientExtensions.put(ExtensionType.server_name, baos.toByteArray()); + return clientExtensions; + } + + @Override + public TlsAuthentication getAuthentication() throws IOException { + return new TlsAuthentication() { + @Override + public void notifyServerCertificate(Certificate serverCertificate) throws IOException { + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + List certs = new LinkedList(); + for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) { + certs.add(cf.generateCertificate(new ByteArrayInputStream(c.getEncoded()))); + } + peertCerts = certs.toArray(new java.security.cert.Certificate[0]); + } catch (CertificateException e) { + System.out.println("Failed to cache server certs" + e); + throw new IOException(e); + } + } + + @Override + public TlsCredentials getClientCredentials(CertificateRequest arg0) throws IOException { + return null; + } + }; + } + }); + } + };//Socket + + } +} \ No newline at end of file From e537267ce7128a4330e663d3e9f48275ab09669a Mon Sep 17 00:00:00 2001 From: ankitdas13 Date: Wed, 24 Aug 2022 18:11:52 +0530 Subject: [PATCH 4/4] added tlsconnectionfactory fix --- src/main/java/com/razorpay/TLSSocketConnectionFactory.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/razorpay/TLSSocketConnectionFactory.java b/src/main/java/com/razorpay/TLSSocketConnectionFactory.java index 9574fd2b..87712d5d 100644 --- a/src/main/java/com/razorpay/TLSSocketConnectionFactory.java +++ b/src/main/java/com/razorpay/TLSSocketConnectionFactory.java @@ -69,9 +69,6 @@ public void handshakeCompleted(HandshakeCompletedEvent event) { // ******************Adding Custom BouncyCastleProvider*********************// @Override public Socket createSocket(Socket socket, final String host, int port, boolean arg3) throws IOException { - if (socket == null) { - socket = new Socket(); - } if (!socket.isConnected()) { socket.connect(new InetSocketAddress(host, port)); }