Skip to content

Commit

Permalink
formatting feedback, java7 (bunq#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
tubbynl committed Jun 20, 2018
1 parent ffb56ad commit c3ae08b
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 98 deletions.
7 changes: 4 additions & 3 deletions src/main/java/com/bunq/sdk/http/ApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ private void setDefaultHeaders(BunqRequestBuilder httpEntity) {
BunqHeader.userAgent.addTo(httpEntity);
BunqHeader.language.addTo(httpEntity);
BunqHeader.region.addTo(httpEntity);
BunqHeader.clientRequestId.addTo(httpEntity,UUID.randomUUID().toString());
BunqHeader.clientRequestId.addTo(httpEntity, UUID.randomUUID().toString());
BunqHeader.geolocation.addTo(httpEntity);
}

Expand All @@ -256,8 +256,8 @@ private void setSessionHeaders(BunqRequestBuilder requestBuilder) {
String sessionToken = apiContext.getSessionToken();

if (sessionToken != null) {
BunqHeader.clientAuthentication.addTo(requestBuilder,sessionToken);
BunqHeader.clientSignature.addTo(requestBuilder,generateSignature(requestBuilder));
BunqHeader.clientAuthentication.addTo(requestBuilder, sessionToken);
BunqHeader.clientSignature.addTo(requestBuilder, generateSignature(requestBuilder));
}
}

Expand Down Expand Up @@ -285,6 +285,7 @@ private BunqResponseRaw createBunqResponseRaw(Response response)
*/
private static String getResponseId(Response response) {
Map<String, String> headerMap = getHeadersMap(response);

return BunqHeader.clientResponseId.getOrDefault(headerMap);
}

Expand Down
55 changes: 39 additions & 16 deletions src/main/java/com/bunq/sdk/http/BunqBasicHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

import okhttp3.Response;

import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class BunqBasicHeader {
/**
* String format constants for signing data
*/
private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": ";
private static final String NEWLINE = "\n";

private final BunqHeader name;
private final String value;

public static BunqBasicHeader get(BunqHeader header,Response response) {
return new BunqBasicHeader(header,response.header(header.getHeader()));
}

public static Optional<BunqBasicHeader> get(String header, String value) {
return BunqHeader.parse(header).map(h->new BunqBasicHeader(h,value));
public static BunqBasicHeader get(BunqHeader header, Response response) {
return new BunqBasicHeader(header, response.header(header.getHeader()));
}

public BunqBasicHeader(BunqHeader name, String value) {
Expand All @@ -35,13 +35,36 @@ public String getValue() {
}

private String forSigning() {
return getName().getHeader()+DELIMITER_HEADER_NAME_AND_VALUE+getValue();
return getName().getHeader() + DELIMITER_HEADER_NAME_AND_VALUE + getValue();
}

public static String collectForSigning(Stream<BunqBasicHeader> headers) {
return headers
.map(BunqBasicHeader::forSigning)
.sorted()
.collect(Collectors.joining(NEWLINE));
public static String collectForSigning(
Collection<BunqBasicHeader> headers,
BunqHeader exclude,
Collection<BunqHeader> includes) {
List<String> headersForSigning = new ArrayList<String>();

for (BunqBasicHeader header:headers) {
if (!header.getName().isBunq() && !includes.contains(header.getName())) {
continue;
}

if (exclude != null && exclude.equals(header.getName())) {
continue;
}

headersForSigning.add(header.forSigning());
}

Collections.sort(headersForSigning);

StringBuffer stringBuffer = new StringBuffer();

for (String header:headersForSigning) {
stringBuffer.append(header);
stringBuffer.append(NEWLINE);
}

return stringBuffer.toString();
}
}
}
64 changes: 45 additions & 19 deletions src/main/java/com/bunq/sdk/http/BunqHeader.java
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
package com.bunq.sdk.http;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

public enum BunqHeader {
attachmentDescription("X-Bunq-Attachment-Description"),
cacheControl("Cache-Control","no-cache"),
cacheControl("Cache-Control", "no-cache"),
contentType("Content-Type"),
clientAuthentication("X-Bunq-Client-Authentication"),
clientEncryptionHMAC("X-Bunq-Client-Encryption-Hmac"),
clientEncryptionIV("X-Bunq-Client-Encryption-Iv"),
clientEncryptionKey("X-Bunq-Client-Encryption-Key"),
clientRequestId("X-Bunq-Client-Request-Id"),
clientSignature("X-Bunq-Client-Signature"),
clientResponseId("X-Bunq-Client-Response-Id","Could not determine response id."),
geolocation("X-Bunq-Geolocation","0 0 0 0 000"),
language("X-Bunq-Language","en_US"),
region("X-Bunq-Region","nl_NL"),
clientResponseId("X-Bunq-Client-Response-Id", "Could not determine response id."),
geolocation("X-Bunq-Geolocation", "0 0 0 0 000"),
language("X-Bunq-Language", "en_US"),
region("X-Bunq-Region", "nl_NL"),
serverSignature("X-Bunq-Server-Signature"),
userAgent("User-Agent","bunq-sdk-java/0.13.1");
userAgent("User-Agent", "bunq-sdk-java/0.13.1");

private static final String PREFIX = "X-Bunq-";

private final String header;
private final String defaultValue;

BunqHeader(String header) {
this(header,null);
this(header, null);
}

BunqHeader(String header, String defaultValue) {
this.header = header;
this.defaultValue = defaultValue;
}

public static Optional<BunqHeader> parse(String value) {
return Stream.of(values()).filter(h->h.equals(value)).findAny();
public static BunqHeader parse(String value) {
for (BunqHeader header:values()) {
if (header.equals(value)) {
return header;
}
}

return null;
}

public String getHeader() {
Expand All @@ -47,16 +52,24 @@ public String getDefaultValue() {
return defaultValue;
}

public void addTo(Map<String,String> headers, String value) {
headers.put(getHeader(),value!=null?value:getDefaultValue());
private String getOrDefault(String value) {
if (value != null) {
return value;
}

return getDefaultValue();
}

public void addTo(Map<String, String> headers, String value) {
headers.put(getHeader(), getOrDefault(value));
}

public void addTo(BunqRequestBuilder requestBuilder) {
addTo(requestBuilder,null);
addTo(requestBuilder, null);
}

public void addTo(BunqRequestBuilder requestBuilder, String value) {
requestBuilder.addHeader(getHeader(),value!=null?value:getDefaultValue());
requestBuilder.addHeader(getHeader(), getOrDefault(value));
}

public boolean equals(String header) {
Expand All @@ -67,8 +80,21 @@ public boolean isBunq() {
return getHeader().startsWith(PREFIX);
}

public String getOrDefault(Map<String,String> headers) {
Optional<String> key = headers.keySet().stream().filter(this::equals).findAny();
return key.map(headers::get).orElse(getDefaultValue());
private String findKey(Collection<String> keys) {
for (String key:keys) {
if (this.equals(key)) {
return key;
}
}

return null;
}

public String getOrDefault(Map<String, String> headers) {
String key = findKey(headers.keySet());
if (key != null && headers.get(key) != null) {
return headers.get(key);
}
return getDefaultValue();
}
}
}
14 changes: 12 additions & 2 deletions src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,21 @@ public BunqRequestBuilder url(URL url) {
return (BunqRequestBuilder) super.url(url);
}

private void addToAllHeader(String name, String value) {
BunqHeader header = BunqHeader.parse(name);

if (header != null) {
this.allHeader.add(new BunqBasicHeader(header, value));
}
}

/**
* {@inheritDoc}
*/
@Override
public BunqRequestBuilder header(String name, String value) {
BunqBasicHeader.get(name,value).ifPresent(this.allHeader::add);
addToAllHeader(name, value);

return (BunqRequestBuilder) super.header(name, value);
}

Expand All @@ -89,7 +98,8 @@ public BunqRequestBuilder header(String name, String value) {
*/
@Override
public BunqRequestBuilder addHeader(String name, String value) {
BunqBasicHeader.get(name,value).ifPresent(this.allHeader::add);
addToAllHeader(name, value);

return (BunqRequestBuilder) super.addHeader(name, value);
}

Expand Down
62 changes: 33 additions & 29 deletions src/main/java/com/bunq/sdk/security/SecurityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import com.bunq.sdk.context.ApiContext;
import com.bunq.sdk.exception.BunqException;
import com.bunq.sdk.exception.UncaughtExceptionError;
import com.bunq.sdk.http.*;
import com.bunq.sdk.http.BunqBasicHeader;
import com.bunq.sdk.http.BunqHeader;
import com.bunq.sdk.http.BunqRequestBuilder;
import com.bunq.sdk.http.HttpMethod;
import okhttp3.Headers;
import okhttp3.Response;
import okio.BufferedSink;
Expand All @@ -30,7 +33,12 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Static lib containing methods for handling encryption.
Expand Down Expand Up @@ -284,7 +292,7 @@ private static void addHeaderClientEncryptionKey(ApiContext apiContext, SecretKe
cipher.init(Cipher.ENCRYPT_MODE, apiContext.getInstallationContext().getPublicKeyServer());
byte[] keyEncrypted = cipher.doFinal(key.getEncoded());
String keyEncryptedEncoded = Base64.getEncoder().encodeToString(keyEncrypted);
BunqHeader.clientEncryptionKey.addTo(customHeaders,keyEncryptedEncoded);
BunqHeader.clientEncryptionKey.addTo(customHeaders, keyEncryptedEncoded);
} catch (GeneralSecurityException exception) {
throw new BunqException(exception.getMessage());
}
Expand All @@ -293,7 +301,7 @@ private static void addHeaderClientEncryptionKey(ApiContext apiContext, SecretKe
private static void addHeaderClientEncryptionIv(byte[] initializationVector, Map<String,
String> customHeaders) {
String initializationVectorEncoded = Base64.getEncoder().encodeToString(initializationVector);
BunqHeader.clientEncryptionIV.addTo(customHeaders,initializationVectorEncoded);
BunqHeader.clientEncryptionIV.addTo(customHeaders, initializationVectorEncoded);
}

private static byte[] encryptRequestBytes(byte[] requestBytes, SecretKey key,
Expand Down Expand Up @@ -326,7 +334,7 @@ private static void addHeaderClientEncryptionHmac(byte[] requestBytes,
bufferedSink.close();
byte[] hmac = mac.doFinal();
String hmacEncoded = Base64.getEncoder().encodeToString(hmac);
BunqHeader.clientEncryptionHMAC.addTo(customHeaders,hmacEncoded);
BunqHeader.clientEncryptionHMAC.addTo(customHeaders, hmacEncoded);
} catch (GeneralSecurityException | IOException exception) {
throw new BunqException(exception.getMessage());
}
Expand Down Expand Up @@ -380,14 +388,11 @@ private static byte[] getEntityBodyBytes(BunqRequestBuilder requestBuilder) thro
}

private static String generateRequestHeadersSortedString(BunqRequestBuilder bunqRequestBuilder) {
return BunqBasicHeader.collectForSigning(bunqRequestBuilder.getAllHeader()
.stream()
.filter(
header ->
header.getName().isBunq() ||
header.getName().equals(BunqHeader.cacheControl) ||
header.getName().equals(BunqHeader.userAgent)
));
return BunqBasicHeader.collectForSigning(
bunqRequestBuilder.getAllHeader(),
null,
Arrays.asList(BunqHeader.cacheControl, BunqHeader.userAgent)
);
}

/**
Expand Down Expand Up @@ -462,9 +467,9 @@ public static void validateResponseSignature(
response.headers()
);
Signature signature = getSignatureInstance();
BunqBasicHeader headerServerSignature = BunqBasicHeader.get(BunqHeader.serverSignature,response);
BunqBasicHeader serverSignature = BunqBasicHeader.get(BunqHeader.serverSignature, response);

byte[] serverSignatureBase64Bytes = headerServerSignature.getValue().getBytes();
byte[] serverSignatureBase64Bytes = serverSignature.getValue().getBytes();
byte[] serverSignatureDecoded = Base64.getDecoder().decode(serverSignatureBase64Bytes);
verifyDataSigned(signature, keyPublicServer, responseBytes, serverSignatureDecoded);
}
Expand All @@ -478,14 +483,15 @@ private static byte[] getResponseBytes(
List<BunqBasicHeader> allResponseHeader = new ArrayList<>();

for (int i = INDEX_FIRST; i < allHeader.names().size(); i++) {
Optional<BunqBasicHeader> header = BunqBasicHeader.get(allHeader.name(i),allHeader.get(allHeader.name(i)));
if(header.isPresent() && !BunqHeader.serverSignature.equals(header.get().getName())) {
allResponseHeader.add(header.get());
BunqHeader header = BunqHeader.parse(allHeader.name(i));

if (header != null && !BunqHeader.serverSignature.equals(header)) {
allResponseHeader.add(new BunqBasicHeader(header, allHeader.get(allHeader.name(i))));
}
}

try {
outputStream.write(getResponseHeadBytes(responseCode,allResponseHeader));
outputStream.write(getResponseHeadBytes(responseCode, allResponseHeader));
outputStream.write(responseBodyBytes);
} catch (IOException exception) {
throw new UncaughtExceptionError(exception);
Expand All @@ -494,20 +500,18 @@ private static byte[] getResponseBytes(
return outputStream.toByteArray();
}

private static byte[] getResponseHeadBytes(int responseCode, List<BunqBasicHeader> responseHeaders) {
String requestHeadString = responseCode + NEWLINE +
generateResponseHeadersSortedString(responseHeaders) + NEWLINE + NEWLINE;
private static byte[] getResponseHeadBytes(int code, List<BunqBasicHeader> headers) {
String requestHeadString = code + NEWLINE +
generateResponseHeadersSortedString(headers) + NEWLINE + NEWLINE;

return requestHeadString.getBytes();
}

private static String generateResponseHeadersSortedString(List<BunqBasicHeader> headers) {
return BunqBasicHeader.collectForSigning(headers
.stream()
.filter(
header ->
header.getName().isBunq() &&
!header.getName().equals(BunqHeader.serverSignature)
));
return BunqBasicHeader.collectForSigning(
headers,
BunqHeader.serverSignature,
Collections.emptyList()
);
}
}
Loading

0 comments on commit c3ae08b

Please sign in to comment.