Skip to content

Commit 59117e8

Browse files
author
Kedar Chandrayan
authored
Merge pull request #34 from ostdotcom/webhooks_api
Webhooks endpoint support
2 parents c54d05d + 575952f commit 59117e8

9 files changed

Lines changed: 353 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
[OST JAVA SDK v2.2.0](https://github.com/ostdotcom/ost-sdk-java/tree/v2.2.0)
2+
---
3+
4+
* Added webhooks module to call webhook management OST APIs.
5+
* Support for verify webhook signature.
6+
17
[OST JAVA SDK v2.1.0](https://github.com/ostdotcom/ost-sdk-java/tree/v2.1.0)
28
---
39

README.md

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ with OST Platform, requiring only three steps:
4242
<dependency>
4343
<groupId>com.ost</groupId>
4444
<artifactId>ost-sdk-java</artifactId>
45-
<version>2.1.0</version>
45+
<version>2.2.0</version>
4646
</dependency>
4747
```
4848

@@ -559,4 +559,88 @@ Get Base Token Detail:
559559
HashMap <String,Object> params = new HashMap<String,Object>();
560560
JsonObject response = baseTokensService.get( params );
561561
System.out.println("response: " + response.toString() );
562+
```
563+
564+
### Webhooks Module
565+
566+
To manage webhooks on the OST Platform Interface, use services provided by the
567+
Chains module. You can use this service to create new webhooks and manage existing
568+
webhooks.
569+
570+
```java
571+
com.ost.services.Webhooks webhooksService = services.webhooks;
572+
```
573+
574+
Create Webhook:
575+
576+
```java
577+
HashMap<String, Object> params = new HashMap<String, Object>();
578+
ArrayList<String> arrayListofTopics = new ArrayList<String>();
579+
arrayListofTopics.add("devices/authorization_initiate");
580+
params.put("url", "https://www.yourdomain12345.com");
581+
params.put("status", "active");
582+
params.put("topics", arrayListofTopics);
583+
JsonObject response = webhooksService.create( params );
584+
System.out.println("response: " + response.toString() );
585+
```
586+
587+
Update Webhook:
588+
589+
```java
590+
HashMap<String, Object> params = new HashMap<String, Object>();
591+
ArrayList<String> arrayListofTopics = new ArrayList<String>();
592+
arrayListofTopics.add("devices/authorization_initiate");
593+
params.put("webhook_id", "4107e308-0146-4c6f-b2f3-617e2c0d2354");
594+
params.put("status", "active");
595+
params.put("topics", arrayListofTopics);
596+
JsonObject response = webhooksService.update( params );
597+
System.out.println("response: " + response.toString() );
598+
```
599+
600+
Get Webhook:
601+
602+
```java
603+
HashMap<String, Object> params = new HashMap<String, Object>();
604+
params.put("webhook_id", "4107e308-0146-4c6f-b2f3-617e2c0d2354");
605+
JsonObject response = webhooksService.get( params );
606+
System.out.println("response: " + response.toString() );
607+
```
608+
609+
Get Webhook List:
610+
611+
```java
612+
HashMap<String, Object> params = new HashMap<String, Object>();
613+
//params.put("limit", 10);
614+
//params.put("pagination_identifier", "eyJsYXN0RXZhbHVhdGVkS2V5Ijp7InVpZCI6eyJTIjoiZDE5NGFhNzUtYWNkNS00ZjQwLWIzZmItZTczYTdjZjdjMGQ5In0sIndhIjp7IlMiOiIweDU4YjQxMDY0NzQ4OWI4ODYzNTliNThmZTIyMjYwZWIxOTYwN2IwZjYifX19");
615+
JsonObject response = webhooksService.getList( params );
616+
System.out.println("response: " + response.toString() );
617+
```
618+
619+
Delete Webhook:
620+
621+
```java
622+
HashMap<String, Object> params = new HashMap<String, Object>();
623+
params.put("webhook_id", "4107e308-0146-4c6f-b2f3-617e2c0d2354");
624+
JsonObject response = webhooksService.deleteWebhook( params );
625+
System.out.println("response: " + response.toString() );
626+
```
627+
628+
Verify webhook request signature:
629+
630+
```java
631+
String webhookEventData = '{"id":"54e3cd1c-afd7-4dcf-9c78-137c56a53582","topic":"transactions/success","created_at":1560838772,"webhook_id":"0823a4ea-5d87-44cf-8ca8-1e5a31bf8e46","version":"v2","data":{"result_type":"transaction","transaction":{"id":"ddebe817-b94f-4b51-9227-f543fae4715a","transaction_hash":"0x7ee737db22b58dc4da3f4ea4830ca709b388d84f31e77106cb79ee09fc6448f9","from":"0x69a581096dbddf6d1e0fff7ebc1254bb7a2647c6","to":"0xc2f0dde92f6f3a3cb13bfff43e2bd136f7dcfe47","nonce":3,"value":"0","gas_price":"1000000000","gas_used":120558,"transaction_fee":"120558000000000","block_confirmation":24,"status":"SUCCESS","updated_timestamp":1560838699,"block_timestamp":1560838698,"block_number":1554246,"rule_name":"Pricer","meta_property":{},"transfers":[{"from":"0xc2f0dde92f6f3a3cb13bfff43e2bd136f7dcfe47","from_user_id":"acfdea7d-278e-4ffc-aacb-4a21398a280c","to":"0x0a754aaab96d634337aac6556312de396a0ca46a","to_user_id":"7bc8e0bd-6761-4604-8f8e-e33f86f81309","amount":"112325386","kind":"transfer"}]}}}' // webhook response should be here
632+
633+
// Get webhoook version from webhook events data.
634+
String version = "v2";
635+
636+
// Get ost-timestamp from the response received in event.
637+
String requestTimestamp = "1559902637";
638+
639+
// Get signature from the response received in event.
640+
String signature = "e9206f9feecccd8f9653a4bdb56ea74531e6528bae8f6de1797aa77dc5235923";
641+
642+
String webhookSecret = "09121ae7614856777fa36d63aca828e0ef14be77fb48fa149e0c0b50fec847a7";
643+
String stringifiedData = webhookEventData;
644+
Boolean response = webhooksService.verifySignature( version, stringifiedData, requestTimestamp, signature, webhookSecret );
645+
System.out.println("response: " + response );
562646
```

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.0
1+
2.2.0

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.ost</groupId>
55
<artifactId>ost-sdk-java</artifactId>
6-
<version>2.1.0-SNAPSHOT</version>
6+
<version>2.2.0-SNAPSHOT</version>
77
<name>OST SDK for Java</name>
88
<description>OST Platform SDK for Java</description>
99
<packaging>jar</packaging>

src/main/java/com/ost/lib/OSTRequestClient.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,26 @@ public OSTRequestClient( Map<String,Object> params) {
123123

124124
private static String GET_REQUEST = "GET";
125125
private static String POST_REQUEST = "POST";
126+
private static String DELETE_REQUEST = "DELETE";
126127
private static String SocketTimeoutExceptionString = "{'success':'false','err':{'code':'GATEWAY_TIMEOUT','internal_id':'SDK(GATEWAY_TIMEOUT)','msg':'','error_data':[]}}";
127128

128129

129130
public JsonObject get(String resource, Map<String, Object> queryParams) throws IOException {
130131
return send(GET_REQUEST, resource, queryParams);
131132
}
133+
132134
public JsonObject post(String resource, Map<String,Object> queryParams) throws IOException {
133135
return send(POST_REQUEST, resource, queryParams);
134136
}
135137

138+
public JsonObject delete(String resource, Map<String,Object> queryParams) throws IOException {
139+
return send(DELETE_REQUEST, resource, queryParams);
140+
}
141+
136142
private JsonObject send(String requestType, String resource, Map<String, Object> mapParams) throws IOException {
137143
// Basic Sanity.
138-
if ( !requestType.equalsIgnoreCase(POST_REQUEST) && !requestType.equalsIgnoreCase(GET_REQUEST) ) {
144+
if ( !requestType.equalsIgnoreCase(POST_REQUEST) && !requestType.equalsIgnoreCase(GET_REQUEST)
145+
&& !requestType.equalsIgnoreCase(DELETE_REQUEST)) {
139146
throw new IOException("Invalid requestType");
140147
}
141148
if ( null == mapParams ) {
@@ -180,7 +187,7 @@ private JsonObject send(String requestType, String resource, Map<String, Object>
180187
paramKey = pair.getParamName();
181188
paramVal = pair.getParamValue();
182189

183-
if (GET_REQUEST.equalsIgnoreCase(requestType)) {
190+
if (GET_REQUEST.equalsIgnoreCase(requestType) || DELETE_REQUEST.equalsIgnoreCase(requestType)) {
184191
urlBuilder.addEncodedQueryParameter(paramKey, paramVal);
185192
} else {
186193
formBodyBuilder.addEncoded(paramKey, paramVal);
@@ -198,7 +205,10 @@ private JsonObject send(String requestType, String resource, Map<String, Object>
198205
Request request;
199206
if (GET_REQUEST.equalsIgnoreCase(requestType)) {
200207
requestBuilder.get().addHeader("content-type", "x-www-form-urlencoded");
201-
} else {
208+
} else if(DELETE_REQUEST.equalsIgnoreCase(requestType)){
209+
requestBuilder.delete().addHeader("content-type", "x-www-form-urlencoded");
210+
}
211+
else {
202212
FormBody formBody = formBodyBuilder.build();
203213
if (DEBUG && VERBOSE) {
204214
for (int i = 0; i < formBody.size(); i++) {

src/main/java/com/ost/services/Manifest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class Manifest extends OSTServiceManifest {
1616
public Devices devices;
1717
public Chains chains;
1818
public BaseTokens baseTokens;
19+
public Webhooks webhooks;
1920

2021

2122
public Manifest( Map<String, Object> params) {
@@ -36,6 +37,7 @@ protected void init() {
3637
this.devices = new Devices( this.request );
3738
this.chains = new Chains( this.request );
3839
this.baseTokens = new BaseTokens( this.request );
40+
this.webhooks = new Webhooks( this.request);
3941
}
4042

4143
}

src/main/java/com/ost/services/OSTAPIService.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,21 @@ public String getUserId(Map<String, Object> params) throws MissingParameter, Inv
118118
return user_id;
119119
}
120120

121+
public String getWebhookId(Map<String, Object> params) throws MissingParameter, InvalidParameter {
122+
String webhook_id = "";
123+
if (null == params || !params.containsKey("webhook_id") || null == params.get("webhook_id")) {
124+
throw new MissingParameter("webhook_id");
125+
}
126+
if (!isValidParameter(params.get("webhook_id"))) {
127+
throw new InvalidParameter("webhook_id");
128+
}
129+
130+
webhook_id = params.get("webhook_id").toString();
131+
params.remove("webhook_id");
132+
133+
return webhook_id;
134+
}
135+
121136
public Boolean isValidParameter(Object params) throws InvalidParameter {
122137
if(params instanceof Number){
123138
return true;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.ost.services;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonObject;
5+
import com.ost.lib.OSTRequestClient;
6+
import okio.Buffer;
7+
import okio.ByteString;
8+
9+
import javax.crypto.Mac;
10+
import javax.crypto.spec.SecretKeySpec;
11+
import java.io.IOException;
12+
import java.security.InvalidKeyException;
13+
import java.security.NoSuchAlgorithmException;
14+
import java.util.Map;
15+
16+
import static com.google.common.base.Charsets.UTF_8;
17+
18+
public class Webhooks extends OSTAPIService {
19+
private static String servicePrefix = "/webhooks";
20+
private static String serviceSuffix = "";
21+
private static final String HMAC_SHA256 = "HmacSHA256";
22+
23+
public Webhooks(OSTRequestClient ostRequestClient) {
24+
super(ostRequestClient, servicePrefix, serviceSuffix);
25+
}
26+
27+
/**
28+
* Create webhook
29+
* @param params Request Params
30+
* @return API Response
31+
*/
32+
public JsonObject create( Map<String,Object> params ) throws IOException {
33+
String resource = this.urlPrefix + "/";
34+
return this.request.post(resource, params);
35+
}
36+
37+
/**
38+
* Update webhook
39+
* @param params Request Params
40+
* @return API Response
41+
*/
42+
public JsonObject update( Map<String,Object> params ) throws IOException, InvalidParameter, MissingParameter {
43+
String resource = this.urlPrefix + "/" + this.getWebhookId( params ) + "/";
44+
return this.request.post(resource, params);
45+
}
46+
47+
/**
48+
* Get webhook
49+
* @param params Request Params
50+
* @return API Response
51+
*/
52+
public JsonObject get( Map<String,Object> params ) throws MissingParameter, IOException, InvalidParameter {
53+
String resource = this.urlPrefix + "/" + this.getWebhookId( params ) + "/";
54+
return this.request.get(resource, params);
55+
}
56+
57+
/**
58+
* Get list of webhooks
59+
* @param params Request Params
60+
* @return API Response
61+
*/
62+
public JsonObject getList( Map<String,Object> params ) throws IOException {
63+
String resource = this.urlPrefix + "/";
64+
return this.request.get(resource, params);
65+
}
66+
67+
/**
68+
* Delete webhook
69+
* @param params Request Params
70+
* @return API Response
71+
*/
72+
public JsonObject deleteWebhook( Map<String,Object> params ) throws MissingParameter, InvalidParameter, IOException {
73+
String resource = this.urlPrefix + "/" + this.getWebhookId( params ) + "/";
74+
return this.request.delete(resource, params);
75+
}
76+
77+
/**
78+
* Verify signature
79+
* @param version
80+
* @param stringifiedData
81+
* @param requestTimestamp
82+
* @param signature
83+
* @return {boolean}
84+
*/
85+
public boolean verifySignature(String version, String stringifiedData, String requestTimestamp, String signature, String webhookSecret) {
86+
87+
if(!(stringifiedData instanceof String)){
88+
Gson gsonObj = new Gson();
89+
stringifiedData = gsonObj.toJson(stringifiedData);
90+
}
91+
92+
Buffer hmacInputBuffer = new Buffer();
93+
hmacInputBuffer.writeUtf8(requestTimestamp);
94+
hmacInputBuffer.writeByte('.');
95+
hmacInputBuffer.writeUtf8(version);
96+
hmacInputBuffer.writeByte('.');
97+
hmacInputBuffer.writeUtf8(stringifiedData);
98+
99+
SecretKeySpec keySpec = new SecretKeySpec( webhookSecret.getBytes( UTF_8 ), HMAC_SHA256);
100+
Mac mac;
101+
try {
102+
mac = Mac.getInstance(HMAC_SHA256);
103+
mac.init(keySpec);
104+
} catch ( NoSuchAlgorithmException e) {
105+
throw new IllegalStateException(e);
106+
} catch (InvalidKeyException e) {
107+
throw new IllegalStateException(e);
108+
}
109+
110+
byte[] bytes = hmacInputBuffer.readByteArray();
111+
byte[] result = mac.doFinal(bytes);
112+
113+
String computedSignature = ByteString.of(result).hex();
114+
115+
return signature.indexOf(computedSignature) >= 0;
116+
}
117+
118+
}

0 commit comments

Comments
 (0)