Skip to content

Commit c9c7f00

Browse files
author
Konstantin Yakushev
committed
Merge branch 'release/1.1.0'
2 parents fdb9d4b + 4fae8a5 commit c9c7f00

File tree

112 files changed

+1503
-1174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+1503
-1174
lines changed

.idea/modules.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group 'com.bunq.sdk'
2-
version '1.0.0'
2+
version '1.1.0'
33

44
apply plugin: 'java'
55
apply plugin: 'maven'

src/main/java/com/bunq/sdk/http/ApiClient.java

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import com.bunq.sdk.exception.UncaughtExceptionError;
1111
import com.bunq.sdk.json.BunqGsonBuilder;
1212
import com.bunq.sdk.security.SecurityUtils;
13-
import com.bunq.sdk.util.BunqUtil;
1413
import com.google.gson.GsonBuilder;
1514
import com.google.gson.JsonArray;
1615
import com.google.gson.JsonElement;
@@ -50,8 +49,6 @@ public class ApiClient {
5049
*/
5150
private static final String ERROR_COULD_NOT_DETERMINE_PINNED_KEY =
5251
"Could not determine pinned key.";
53-
private static final String ERROR_COULD_NOT_DETERMINE_RESPONSE_ID =
54-
"Could not determine response id.";
5552

5653
/**
5754
* Endpoints not requiring active session for the request to succeed.
@@ -65,40 +62,12 @@ public class ApiClient {
6562
SESSION_SERVER_URL
6663
);
6764

68-
/**
69-
* Header constants.
70-
*/
71-
public static final String HEADER_ATTACHMENT_DESCRIPTION = "X-Bunq-Attachment-Description";
72-
public static final String HEADER_CONTENT_TYPE = "Content-Type";
73-
public static final String HEADER_USER_AGENT = "User-Agent";
74-
public static final String HEADER_CACHE_CONTROL = "Cache-Control";
75-
public static final String HEADER_LANGUAGE = "X-Bunq-Language";
76-
public static final String HEADER_REGION = "X-Bunq-Region";
77-
public static final String HEADER_REQUEST_ID = "X-Bunq-Client-Request-Id";
78-
public static final String HEADER_GEOLOCATION = "X-Bunq-Geolocation";
79-
private static final String HEADER_SIGNATURE = "X-Bunq-Client-Signature";
80-
private static final String HEADER_AUTHENTICATION = "X-Bunq-Client-Authentication";
81-
private static final String HEADER_RESPONSE_ID_LOWER_CASE = "x-bunq-client-response-id";
82-
private static final String HEADER_RESPONSE_ID_UPPER_CASE = "X-Bunq-Client-Response-Id";
83-
8465
/**
8566
* Field constants.
8667
*/
8768
private static final String FIELD_ERROR = "Error";
8869
private static final String FIELD_ERROR_DESCRIPTION = "error_description";
8970

90-
/**
91-
* Header value to disable the cache control.
92-
*/
93-
public static final String CACHE_CONTROL_NONE = "no-cache";
94-
95-
/**
96-
* Prefix for bunq's own headers.
97-
*/
98-
private static final String USER_AGENT_BUNQ = "bunq-sdk-java/1.0.0";
99-
public static final String LANGUAGE_EN_US = "en_US";
100-
public static final String REGION_NL_NL = "nl_NL";
101-
public static final String GEOLOCATION_ZERO = "0 0 0 0 000";
10271
private static final String SCHEME_HTTPS = "https";
10372

10473
/**
@@ -183,11 +152,14 @@ public BunqResponseRaw post(
183152
customHeaders = new HashMap<>();
184153
}
185154

186-
BunqRequestBody bunqRequestBody = BunqRequestBody.create(ContentType.JSON.getMediaType(), requestBodyBytes);
155+
BunqRequestBody bunqRequestBody = BunqRequestBody.create(
156+
ContentType.JSON.getMediaType(),
157+
requestBodyBytes
158+
);
187159

188-
if (customHeaders.containsKey(HEADER_CONTENT_TYPE)) {
160+
if (customHeaders.containsKey(BunqHeader.CONTENT_TYPE.getHeaderName())) {
189161
bunqRequestBody = BunqRequestBody.create(
190-
MediaType.parse(customHeaders.get(HEADER_CONTENT_TYPE)),
162+
MediaType.parse(customHeaders.get(BunqHeader.CONTENT_TYPE.getHeaderName())),
191163
requestBodyBytes
192164
);
193165
}
@@ -254,13 +226,13 @@ private void setHeaders(BunqRequestBuilder requestBuilder, Map<String, String> c
254226

255227
/**
256228
*/
257-
private void setDefaultHeaders(Request.Builder httpEntity) {
258-
httpEntity.addHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NONE);
259-
httpEntity.addHeader(HEADER_USER_AGENT, getVersion());
260-
httpEntity.addHeader(HEADER_LANGUAGE, LANGUAGE_EN_US);
261-
httpEntity.addHeader(HEADER_REGION, REGION_NL_NL);
262-
httpEntity.addHeader(HEADER_REQUEST_ID, UUID.randomUUID().toString());
263-
httpEntity.addHeader(HEADER_GEOLOCATION, GEOLOCATION_ZERO);
229+
private void setDefaultHeaders(BunqRequestBuilder httpEntity) {
230+
BunqHeader.CACHE_CONTROL.addTo(httpEntity);
231+
BunqHeader.USER_AGENT.addTo(httpEntity);
232+
BunqHeader.LANGUAGE.addTo(httpEntity);
233+
BunqHeader.REGION.addTo(httpEntity);
234+
BunqHeader.CLIENT_REQUEST_ID.addTo(httpEntity, UUID.randomUUID().toString());
235+
BunqHeader.GEOLOCATION.addTo(httpEntity);
264236
}
265237

266238
/**
@@ -277,8 +249,8 @@ private void setSessionHeaders(BunqRequestBuilder requestBuilder) {
277249
String sessionToken = apiContext.getSessionToken();
278250

279251
if (sessionToken != null) {
280-
requestBuilder.addHeader(HEADER_AUTHENTICATION, sessionToken);
281-
requestBuilder.addHeader(HEADER_SIGNATURE, generateSignature(requestBuilder));
252+
BunqHeader.CLIENT_AUTHENTICATION.addTo(requestBuilder, sessionToken);
253+
BunqHeader.CLIENT_SIGNATURE.addTo(requestBuilder, generateSignature(requestBuilder));
282254
}
283255
}
284256

@@ -289,12 +261,6 @@ private String generateSignature(BunqRequestBuilder requestBuilder) {
289261
apiContext.getInstallationContext().getKeyPairClient());
290262
}
291263

292-
/**
293-
*/
294-
private String getVersion() {
295-
return USER_AGENT_BUNQ;
296-
}
297-
298264
/**
299265
*/
300266
private BunqResponseRaw createBunqResponseRaw(Response response)
@@ -313,15 +279,7 @@ private BunqResponseRaw createBunqResponseRaw(Response response)
313279
private static String getResponseId(Response response) {
314280
Map<String, String> headerMap = getHeadersMap(response);
315281

316-
if (headerMap.containsKey(HEADER_RESPONSE_ID_LOWER_CASE)) {
317-
return headerMap.get(HEADER_RESPONSE_ID_LOWER_CASE);
318-
} else {
319-
return BunqUtil.getValueFromMapOrDefault(
320-
headerMap,
321-
HEADER_RESPONSE_ID_UPPER_CASE,
322-
ERROR_COULD_NOT_DETERMINE_RESPONSE_ID
323-
);
324-
}
282+
return BunqHeader.CLIENT_RESPONSE_ID.getHeaderValueOrDefault(headerMap);
325283
}
326284

327285
/**

src/main/java/com/bunq/sdk/http/BunqBasicHeader.java

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,83 @@
11
package com.bunq.sdk.http;
22

3-
public class BunqBasicHeader implements Comparable<BunqBasicHeader> {
4-
private String name;
5-
private String value;
3+
import okhttp3.Response;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collection;
7+
import java.util.Collections;
8+
import java.util.List;
69

10+
public class BunqBasicHeader implements Comparable<BunqBasicHeader> {
711
/**
12+
* String format constants for signing data
813
*/
9-
public BunqBasicHeader(String name, String value) {
14+
private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": ";
15+
private static final String NEWLINE = "\n";
16+
17+
private final BunqHeader name;
18+
private final String value;
19+
20+
public static BunqBasicHeader get(BunqHeader header, Response response) {
21+
return new BunqBasicHeader(header, response.header(header.getHeaderName()));
22+
}
23+
24+
public BunqBasicHeader(BunqHeader name, String value) {
1025
this.name = name;
1126
this.value = value;
1227
}
1328

14-
/**
15-
*/
16-
public String getName() {
29+
public BunqHeader getName() {
1730
return name;
1831
}
1932

20-
/**
21-
*/
2233
public String getValue() {
2334
return value;
2435
}
2536

37+
private String forSigning() {
38+
return getName().getHeaderName() + DELIMITER_HEADER_NAME_AND_VALUE + getValue();
39+
}
40+
41+
public static String collectForSigning(
42+
Collection<BunqBasicHeader> allBasicHeader,
43+
BunqHeader exclude,
44+
Collection<BunqHeader> allNonBunqHeaderToInclude) {
45+
List<String> allHeaderForSigning = new ArrayList<String>();
46+
47+
for (BunqBasicHeader basicHeader:allBasicHeader) {
48+
addHeaderForSigningIfNeeded(basicHeader, allHeaderForSigning, allNonBunqHeaderToInclude);
49+
}
50+
51+
Collections.sort(allHeaderForSigning);
52+
53+
return formatAllHeaderForSigning(allHeaderForSigning);
54+
}
55+
56+
private static void addHeaderForSigningIfNeeded(
57+
BunqBasicHeader basicHeader,
58+
List<String> allHeaderForSigning,
59+
Collection<BunqHeader> allNonBunqHeaderToInclude
60+
) {
61+
BunqHeader header = basicHeader.getName();
62+
63+
if (header.isBunq() || allNonBunqHeaderToInclude.contains(header)) {
64+
allHeaderForSigning.add(basicHeader.forSigning());
65+
}
66+
}
67+
68+
private static String formatAllHeaderForSigning(List<String> allHeaderForSigning) {
69+
StringBuilder stringBuilder = new StringBuilder();
70+
71+
for (String header: allHeaderForSigning) {
72+
stringBuilder.append(header);
73+
stringBuilder.append(NEWLINE);
74+
}
75+
76+
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(NEWLINE));
77+
78+
return stringBuilder.toString();
79+
}
80+
2681
@Override
2782
public int compareTo(BunqBasicHeader o) {
2883
return getName().compareTo(o.getName());
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.bunq.sdk.http;
2+
3+
import java.util.Collection;
4+
import java.util.Map;
5+
6+
public enum BunqHeader {
7+
ATTACHMENT_DESCRIPTION("X-Bunq-Attachment-Description"),
8+
CACHE_CONTROL("Cache-Control", "no-cache"),
9+
CLIENT_AUTHENTICATION("X-Bunq-Client-Authentication"),
10+
CLIENT_ENCRYPTION_HMAC("X-Bunq-Client-Encryption-Hmac"),
11+
CLIENT_ENCRYPTION_IV("X-Bunq-Client-Encryption-Iv"),
12+
CLIENT_ENCRYPTION_KEY("X-Bunq-Client-Encryption-Key"),
13+
CLIENT_REQUEST_ID("X-Bunq-Client-Request-Id"),
14+
CLIENT_RESPONSE_ID("X-Bunq-Client-Response-Id", "Could not determine response id."),
15+
CLIENT_SIGNATURE("X-Bunq-Client-Signature"),
16+
CONTENT_TYPE("Content-Type"),
17+
GEOLOCATION("X-Bunq-Geolocation", "0 0 0 0 000"),
18+
LANGUAGE("X-Bunq-Language", "en_US"),
19+
REGION("X-Bunq-Region", "nl_NL"),
20+
SERVER_SIGNATURE("X-Bunq-Server-Signature"),
21+
USER_AGENT("User-Agent", "bunq-sdk-java/0.13.1");
22+
23+
private static final String PREFIX = "X-Bunq-";
24+
25+
private final String header;
26+
private final String defaultValue;
27+
28+
BunqHeader(String header) {
29+
this(header, null);
30+
}
31+
32+
BunqHeader(String header, String defaultValue) {
33+
this.header = header;
34+
this.defaultValue = defaultValue;
35+
}
36+
37+
public static BunqHeader parseHeaderOrNull(String value) {
38+
for (BunqHeader header : values()) {
39+
if (header.equals(value)) {
40+
return header;
41+
}
42+
}
43+
44+
return null;
45+
}
46+
47+
public String getHeaderName() {
48+
return header;
49+
}
50+
51+
public String getDefaultValue() {
52+
return defaultValue;
53+
}
54+
55+
private String getHeaderValueOrDefault(String value) {
56+
if (value != null) {
57+
return value;
58+
}
59+
60+
return getDefaultValue();
61+
}
62+
63+
public void addTo(Map<String, String> headers, String value) {
64+
headers.put(getHeaderName(), getHeaderValueOrDefault(value));
65+
}
66+
67+
public void addTo(BunqRequestBuilder requestBuilder) {
68+
addTo(requestBuilder, null);
69+
}
70+
71+
public void addTo(BunqRequestBuilder requestBuilder, String value) {
72+
requestBuilder.addHeader(getHeaderName(), getHeaderValueOrDefault(value));
73+
}
74+
75+
public boolean equals(String header) {
76+
return getHeaderName().equalsIgnoreCase(header);
77+
}
78+
79+
public boolean isBunq() {
80+
return getHeaderName().startsWith(PREFIX);
81+
}
82+
83+
private String findKeyOrNull(Collection<String> keys) {
84+
for (String key : keys) {
85+
if (this.equals(key)) {
86+
return key;
87+
}
88+
}
89+
90+
return null;
91+
}
92+
93+
public String getHeaderValueOrDefault(Map<String, String> headers) {
94+
String key = findKeyOrNull(headers.keySet());
95+
96+
if (key != null && headers.get(key) != null) {
97+
return headers.get(key);
98+
}
99+
100+
return getDefaultValue();
101+
}
102+
103+
}

src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,20 @@ public BunqRequestBuilder url(URL url) {
7575
return (BunqRequestBuilder) super.url(url);
7676
}
7777

78+
private void addToAllHeader(String name, String value) {
79+
BunqHeader header = BunqHeader.parseHeaderOrNull(name);
80+
81+
if (header != null) {
82+
this.allHeader.add(new BunqBasicHeader(header, value));
83+
}
84+
}
85+
7886
/**
7987
* {@inheritDoc}
8088
*/
8189
@Override
8290
public BunqRequestBuilder header(String name, String value) {
83-
this.allHeader.add(new BunqBasicHeader(name, value));
91+
addToAllHeader(name, value);
8492

8593
return (BunqRequestBuilder) super.header(name, value);
8694
}
@@ -90,7 +98,7 @@ public BunqRequestBuilder header(String name, String value) {
9098
*/
9199
@Override
92100
public BunqRequestBuilder addHeader(String name, String value) {
93-
this.allHeader.add(new BunqBasicHeader(name, value));
101+
addToAllHeader(name, value);
94102

95103
return (BunqRequestBuilder) super.addHeader(name, value);
96104
}
@@ -205,13 +213,8 @@ public BunqRequestBody getBody() {
205213

206214
/**
207215
*/
208-
public List<BunqBasicHeader> getAllHeaderAsList() {
216+
public List<BunqBasicHeader> getAllHeader() {
209217
return this.allHeader;
210218
}
211219

212-
/**
213-
*/
214-
public BunqBasicHeader[] getAllHeaderAsArray() {
215-
return this.allHeader.toArray(new BunqBasicHeader[this.allHeader.size()]);
216-
}
217220
}

0 commit comments

Comments
 (0)