From 64867163544d0ba45cea2f7edc7f395ada53afff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Sun, 17 Jun 2018 19:35:47 +0200 Subject: [PATCH 1/8] extracted header-magic as enum (bunq/sdk_java#93) BunqHeader, and added some junit tests on it --- .../java/com/bunq/sdk/http/ApiClient.java | 62 +++------------- .../com/bunq/sdk/http/BunqBasicHeader.java | 23 +++--- .../java/com/bunq/sdk/http/BunqHeader.java | 74 +++++++++++++++++++ .../com/bunq/sdk/security/SecurityUtils.java | 73 ++++-------------- .../java/com/bunq/sdk/BunqSdkTestBase.java | 12 +-- .../com/bunq/sdk/http/BunqHeaderTest.java | 49 ++++++++++++ .../endpoint/AttachmentPublicTest.java | 7 +- .../model/generated/endpoint/AvatarTest.java | 7 +- 8 files changed, 173 insertions(+), 134 deletions(-) create mode 100644 src/main/java/com/bunq/sdk/http/BunqHeader.java create mode 100644 src/test/java/com/bunq/sdk/http/BunqHeaderTest.java diff --git a/src/main/java/com/bunq/sdk/http/ApiClient.java b/src/main/java/com/bunq/sdk/http/ApiClient.java index dc1b0727..2b16eda1 100644 --- a/src/main/java/com/bunq/sdk/http/ApiClient.java +++ b/src/main/java/com/bunq/sdk/http/ApiClient.java @@ -47,7 +47,6 @@ public class ApiClient { * Error constants. */ private static final String ERROR_AMI_ENVIRONMENT_NOT_EXPECTED = "ApiEnvironment type \"%s\" is unexpected"; - private static final String ERROR_COULD_NOT_DETERMINE_RESPONSE_ID = "Could not determine response id."; /** * Endpoints not requiring active session for the request to succeed. @@ -61,40 +60,12 @@ public class ApiClient { SESSION_SERVER_URL ); - /** - * Header constants. - */ - public static final String HEADER_ATTACHMENT_DESCRIPTION = "X-Bunq-Attachment-Description"; - public static final String HEADER_CONTENT_TYPE = "Content-Type"; - public static final String HEADER_USER_AGENT = "User-Agent"; - public static final String HEADER_CACHE_CONTROL = "Cache-Control"; - public static final String HEADER_LANGUAGE = "X-Bunq-Language"; - public static final String HEADER_REGION = "X-Bunq-Region"; - public static final String HEADER_REQUEST_ID = "X-Bunq-Client-Request-Id"; - public static final String HEADER_GEOLOCATION = "X-Bunq-Geolocation"; - private static final String HEADER_SIGNATURE = "X-Bunq-Client-Signature"; - private static final String HEADER_AUTHENTICATION = "X-Bunq-Client-Authentication"; - private static final String HEADER_RESPONSE_ID_LOWER_CASE = "x-bunq-client-response-id"; - private static final String HEADER_RESPONSE_ID_UPPER_CASE = "X-Bunq-Client-Response-Id"; - /** * Field constants. */ private static final String FIELD_ERROR = "Error"; private static final String FIELD_ERROR_DESCRIPTION = "error_description"; - /** - * Header value to disable the cache control. - */ - public static final String CACHE_CONTROL_NONE = "no-cache"; - - /** - * Prefix for bunq's own headers. - */ - private static final String USER_AGENT_BUNQ = "bunq-sdk-java/0.13.1"; - public static final String LANGUAGE_EN_US = "en_US"; - public static final String REGION_NL_NL = "nl_NL"; - public static final String GEOLOCATION_ZERO = "0 0 0 0 000"; private static final String SCHEME_HTTPS = "https"; /** @@ -193,9 +164,9 @@ public BunqResponseRaw post( BunqRequestBody bunqRequestBody = BunqRequestBody.create(ContentType.JSON.getMediaType(), requestBodyBytes); - if (customHeaders.containsKey(HEADER_CONTENT_TYPE)) { + if (customHeaders.containsKey(BunqHeader.contentType.getHeader())) { bunqRequestBody = BunqRequestBody.create( - MediaType.parse(customHeaders.get(HEADER_CONTENT_TYPE)), + MediaType.parse(customHeaders.get(BunqHeader.contentType.getHeader())), requestBodyBytes ); } @@ -262,13 +233,13 @@ private void setHeaders(BunqRequestBuilder requestBuilder, Map c /** */ - private void setDefaultHeaders(Request.Builder httpEntity) { - httpEntity.addHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NONE); - httpEntity.addHeader(HEADER_USER_AGENT, getVersion()); - httpEntity.addHeader(HEADER_LANGUAGE, LANGUAGE_EN_US); - httpEntity.addHeader(HEADER_REGION, REGION_NL_NL); - httpEntity.addHeader(HEADER_REQUEST_ID, UUID.randomUUID().toString()); - httpEntity.addHeader(HEADER_GEOLOCATION, GEOLOCATION_ZERO); + private void setDefaultHeaders(BunqRequestBuilder httpEntity) { + BunqHeader.cacheControl.addTo(httpEntity); + BunqHeader.userAgent.addTo(httpEntity); + BunqHeader.language.addTo(httpEntity); + BunqHeader.region.addTo(httpEntity); + BunqHeader.clientRequestId.addTo(httpEntity,UUID.randomUUID().toString()); + BunqHeader.geolocation.addTo(httpEntity); } /** @@ -285,8 +256,8 @@ private void setSessionHeaders(BunqRequestBuilder requestBuilder) { String sessionToken = apiContext.getSessionToken(); if (sessionToken != null) { - requestBuilder.addHeader(HEADER_AUTHENTICATION, sessionToken); - requestBuilder.addHeader(HEADER_SIGNATURE, generateSignature(requestBuilder)); + BunqHeader.clientAuthentication.addTo(requestBuilder,sessionToken); + BunqHeader.clientSignature.addTo(requestBuilder,generateSignature(requestBuilder)); } } @@ -297,12 +268,6 @@ private String generateSignature(BunqRequestBuilder requestBuilder) { apiContext.getInstallationContext().getKeyPairClient()); } - /** - */ - private String getVersion() { - return USER_AGENT_BUNQ; - } - /** */ private BunqResponseRaw createBunqResponseRaw(Response response) @@ -320,10 +285,7 @@ private BunqResponseRaw createBunqResponseRaw(Response response) */ private static String getResponseId(Response response) { Map headerMap = getHeadersMap(response); - - if (headerMap.containsKey(HEADER_RESPONSE_ID_LOWER_CASE)) { - return headerMap.get(HEADER_RESPONSE_ID_LOWER_CASE); - } else return headerMap.getOrDefault(HEADER_RESPONSE_ID_UPPER_CASE, ERROR_COULD_NOT_DETERMINE_RESPONSE_ID); + return BunqHeader.clientResponseId.getOrDefault(headerMap); } /** diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index dc089ae8..c3206eb4 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -1,26 +1,29 @@ package com.bunq.sdk.http; +import okhttp3.Response; + public class BunqBasicHeader { - private String name; - private String value; + 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 BunqBasicHeader(String name, String value) { + this(BunqHeader.parse(name).get(),value); + } + + public BunqBasicHeader(BunqHeader name, String value) { this.name = name; this.value = value; } - /** - */ - public String getName() { + public BunqHeader getName() { return name; } - /** - */ public String getValue() { return value; } - } diff --git a/src/main/java/com/bunq/sdk/http/BunqHeader.java b/src/main/java/com/bunq/sdk/http/BunqHeader.java new file mode 100644 index 00000000..865d18f9 --- /dev/null +++ b/src/main/java/com/bunq/sdk/http/BunqHeader.java @@ -0,0 +1,74 @@ +package com.bunq.sdk.http; + +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"), + 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"), + serverSignature("X-Bunq-Server-Signature"), + 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); + } + + BunqHeader(String header, String defaultValue) { + this.header = header; + this.defaultValue = defaultValue; + } + + public static Optional parse(String value) { + return Stream.of(values()).filter(h->h.equals(value)).findAny(); + } + + public String getHeader() { + return header; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void addTo(Map headers, String value) { + headers.put(getHeader(),value!=null?value:getDefaultValue()); + } + + public void addTo(BunqRequestBuilder requestBuilder) { + addTo(requestBuilder,null); + } + + public void addTo(BunqRequestBuilder requestBuilder, String value) { + requestBuilder.addHeader(getHeader(),value!=null?value:getDefaultValue()); + } + + public boolean equals(String header) { + return getHeader().equalsIgnoreCase(header); + } + + public boolean isBunq() { + return getHeader().startsWith(PREFIX); + } + + public String getOrDefault(Map headers) { + Optional key = headers.keySet().stream().filter(this::equals).findAny(); + return key.map(headers::get).orElse(getDefaultValue()); + } +} \ No newline at end of file diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index 4ac676ee..ed42e634 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -3,10 +3,7 @@ import com.bunq.sdk.context.ApiContext; import com.bunq.sdk.exception.BunqException; import com.bunq.sdk.exception.UncaughtExceptionError; -import com.bunq.sdk.http.ApiClient; -import com.bunq.sdk.http.BunqBasicHeader; -import com.bunq.sdk.http.BunqRequestBuilder; -import com.bunq.sdk.http.HttpMethod; +import com.bunq.sdk.http.*; import okhttp3.Headers; import okhttp3.Response; import okio.BufferedSink; @@ -38,8 +35,6 @@ import java.util.Base64; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -72,14 +67,6 @@ public final class SecurityUtils { private static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; private static final int KEY_PAIR_GENERATOR_KEY_SIZE = 2048; - /** - * Encryption-specific headers. - */ - private static final String HEADER_CLIENT_ENCRYPTION_HMAC = "X-Bunq-Client-Encryption-Hmac"; - private static final String HEADER_CLIENT_ENCRYPTION_IV = "X-Bunq-Client-Encryption-Iv"; - private static final String HEADER_CLIENT_ENCRYPTION_KEY = "X-Bunq-Client-Encryption-Key"; - private static final String HEADER_SERVER_SIGNATURE = "X-Bunq-Server-Signature"; - /** * The MAC algorithm to use for calculating and verifying the HMAC. */ @@ -139,26 +126,14 @@ public final class SecurityUtils { /** * Delimiter constants for building the data to sign. */ - private static final String HEADER_NAME_PREFIX_X_BUNQ = "X-Bunq-"; private static final String DELIMITER_METHOD_PATH = " "; private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": "; - /** - * Regex constants. - */ - private static final String REGEX_FOR_LOWERCASE_HEADERS = "(-[a-z])"; - /** * The index of the first item in an array. */ private static final int INDEX_FIRST = 0; - /** - * Substring constants. - */ - private static final int SUBSTRING_BEGIN_INDEX_FIRST_CHAR = 0; - private static final int SUBSTRING_END_INDEX_FIRST_CHAR = 1; - /** */ private SecurityUtils() { @@ -315,7 +290,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); - customHeaders.put(HEADER_CLIENT_ENCRYPTION_KEY, keyEncryptedEncoded); + BunqHeader.clientEncryptionKey.addTo(customHeaders,keyEncryptedEncoded); } catch (GeneralSecurityException exception) { throw new BunqException(exception.getMessage()); } @@ -324,8 +299,7 @@ private static void addHeaderClientEncryptionKey(ApiContext apiContext, SecretKe private static void addHeaderClientEncryptionIv(byte[] initializationVector, Map customHeaders) { String initializationVectorEncoded = Base64.getEncoder().encodeToString(initializationVector); - - customHeaders.put(HEADER_CLIENT_ENCRYPTION_IV, initializationVectorEncoded); + BunqHeader.clientEncryptionIV.addTo(customHeaders,initializationVectorEncoded); } private static byte[] encryptRequestBytes(byte[] requestBytes, SecretKey key, @@ -358,7 +332,7 @@ private static void addHeaderClientEncryptionHmac(byte[] requestBytes, bufferedSink.close(); byte[] hmac = mac.doFinal(); String hmacEncoded = Base64.getEncoder().encodeToString(hmac); - customHeaders.put(HEADER_CLIENT_ENCRYPTION_HMAC, hmacEncoded); + BunqHeader.clientEncryptionHMAC.addTo(customHeaders,hmacEncoded); } catch (GeneralSecurityException | IOException exception) { throw new BunqException(exception.getMessage()); } @@ -415,9 +389,9 @@ private static String generateRequestHeadersSortedString(BunqRequestBuilder bunq return Arrays.stream(bunqRequestBuilder.getAllHeaderAsArray()) .filter( header -> - header.getName().startsWith(HEADER_NAME_PREFIX_X_BUNQ) || - header.getName().equals(ApiClient.HEADER_CACHE_CONTROL) || - header.getName().equals(ApiClient.HEADER_USER_AGENT) + header.getName().isBunq() || + header.getName().equals(BunqHeader.cacheControl) || + header.getName().equals(BunqHeader.userAgent) ) .map(header -> header.getName() + DELIMITER_HEADER_NAME_AND_VALUE + header.getValue()) .sorted() @@ -496,10 +470,8 @@ public static void validateResponseSignature( response.headers() ); Signature signature = getSignatureInstance(); - BunqBasicHeader headerServerSignature = new BunqBasicHeader( - HEADER_SERVER_SIGNATURE, - response.header(HEADER_SERVER_SIGNATURE) - ); + BunqBasicHeader headerServerSignature = BunqBasicHeader.get(BunqHeader.serverSignature,response); + byte[] serverSignatureBase64Bytes = headerServerSignature.getValue().getBytes(); byte[] serverSignatureDecoded = Base64.getDecoder().decode(serverSignatureBase64Bytes); verifyDataSigned(signature, keyPublicServer, responseBytes, serverSignatureDecoded); @@ -514,14 +486,10 @@ private static byte[] getResponseBytes( List allResponseHeader = new ArrayList<>(); for (int i = INDEX_FIRST; i < allHeader.names().size(); i++) { - if (allHeader.name(i).equals(HEADER_SERVER_SIGNATURE)) { + if (BunqHeader.serverSignature.getHeader().equals(allHeader.name(i))) { continue; } - - allResponseHeader.add(new BunqBasicHeader( - getHeaderNameCorrectlyCased(allHeader.name(i)), - allHeader.get(allHeader.name(i)) - )); + allResponseHeader.add(new BunqBasicHeader(allHeader.name(i),allHeader.get(allHeader.name(i)))); } try { @@ -539,21 +507,6 @@ private static byte[] getResponseBytes( return outputStream.toByteArray(); } - private static String getHeaderNameCorrectlyCased(String headerName) { - headerName = headerName.toLowerCase(); - headerName = headerName.substring(SUBSTRING_BEGIN_INDEX_FIRST_CHAR, SUBSTRING_END_INDEX_FIRST_CHAR).toUpperCase() - + headerName.substring(SUBSTRING_END_INDEX_FIRST_CHAR); - Pattern pattern = Pattern.compile(REGEX_FOR_LOWERCASE_HEADERS); - Matcher matcher = pattern.matcher(headerName); - - while (matcher.find()) { - String result = matcher.group(); - headerName = headerName.replace(result, result.toUpperCase()); - } - - return headerName; - } - private static byte[] getResponseHeadBytes(int responseCode, BunqBasicHeader[] responseHeaders) { String requestHeadString = responseCode + NEWLINE + generateResponseHeadersSortedString(responseHeaders) + NEWLINE + NEWLINE; @@ -565,8 +518,8 @@ private static String generateResponseHeadersSortedString(BunqBasicHeader[] resp return Arrays.stream(responseHeaders) .filter( header -> - header.getName().startsWith(HEADER_NAME_PREFIX_X_BUNQ) && - !header.getName().equals(HEADER_SERVER_SIGNATURE) + header.getName().isBunq() && + !header.getName().equals(BunqHeader.serverSignature) ) .map(header -> header.getName() + DELIMITER_HEADER_NAME_AND_VALUE + header.getValue()) .sorted() diff --git a/src/test/java/com/bunq/sdk/BunqSdkTestBase.java b/src/test/java/com/bunq/sdk/BunqSdkTestBase.java index 96b199f5..825bf36d 100644 --- a/src/test/java/com/bunq/sdk/BunqSdkTestBase.java +++ b/src/test/java/com/bunq/sdk/BunqSdkTestBase.java @@ -4,7 +4,7 @@ import com.bunq.sdk.context.ApiEnvironmentType; import com.bunq.sdk.context.BunqContext; import com.bunq.sdk.exception.BunqException; -import com.bunq.sdk.http.ApiClient; +import com.bunq.sdk.http.BunqHeader; import com.bunq.sdk.http.BunqResponse; import com.bunq.sdk.model.generated.endpoint.CashRegister; import com.bunq.sdk.model.generated.endpoint.MonetaryAccountBank; @@ -121,11 +121,11 @@ private static SandboxUser generateNewSandboxUser() { URL_PATH_SANDBOX_USER ) .post(RequestBody.create(null, new byte[INDEX_FIRST])) - .addHeader(ApiClient.HEADER_REQUEST_ID, UUID.randomUUID().toString()) - .addHeader(ApiClient.HEADER_CACHE_CONTROL, ApiClient.CACHE_CONTROL_NONE) - .addHeader(ApiClient.HEADER_GEOLOCATION, ApiClient.GEOLOCATION_ZERO) - .addHeader(ApiClient.HEADER_LANGUAGE, ApiClient.LANGUAGE_EN_US) - .addHeader(ApiClient.HEADER_REGION, ApiClient.REGION_NL_NL) + .addHeader(BunqHeader.clientRequestId.getHeader(), UUID.randomUUID().toString()) + .addHeader(BunqHeader.cacheControl.getHeader(), BunqHeader.cacheControl.getDefaultValue()) + .addHeader(BunqHeader.geolocation.getHeader(), BunqHeader.geolocation.getDefaultValue()) + .addHeader(BunqHeader.language.getHeader(), BunqHeader.language.getDefaultValue()) + .addHeader(BunqHeader.region.getHeader(), BunqHeader.region.getDefaultValue()) .build(); try { diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java new file mode 100644 index 00000000..244e92d6 --- /dev/null +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -0,0 +1,49 @@ +package com.bunq.sdk.http; + +import org.junit.Test; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.*; + +public class BunqHeaderTest { + @Test + public void parse() { + // parse works case-insensitive + assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("X-Bunq-Client-Response-Id").get()); + assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("x-bunq-client-response-id").get()); + } + + @Test + public void isBunq() { + List nonBunqHeaders = Arrays.asList(BunqHeader.cacheControl,BunqHeader.contentType,BunqHeader.userAgent); + + assertEquals(nonBunqHeaders, Stream.of(BunqHeader.values()).filter(h->!h.isBunq()).collect(Collectors.toList())); + } + + @Test + public void getOrDefault() { + BunqHeader h = BunqHeader.clientResponseId; + + assertEquals("test-id",h.getOrDefault(Collections.singletonMap("x-bunq-client-response-id","test-id"))); + assertEquals("Could not determine response id.",h.getOrDefault(Collections.singletonMap("x-bunq-some-other-header","test-id"))); + assertEquals("Could not determine response id.",h.getOrDefault(Collections.emptyMap())); + } + + @Test + public void addToMap() { + Map headers = new HashMap<>(); + + //sut + BunqHeader.language.addTo(headers,null); + BunqHeader.geolocation.addTo(headers,null); + BunqHeader.userAgent.addTo(headers,"test-agent"); + + // verify + assertEquals("en_US",headers.get("X-Bunq-Language")); + assertEquals("0 0 0 0 000",headers.get("X-Bunq-Geolocation")); + assertEquals("test-agent",headers.get("User-Agent")); + } +} \ No newline at end of file diff --git a/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java b/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java index f45e791d..48eca29f 100644 --- a/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java +++ b/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java @@ -3,6 +3,7 @@ import com.bunq.sdk.BunqSdkTestBase; import com.bunq.sdk.exception.BunqException; import com.bunq.sdk.http.ApiClient; +import com.bunq.sdk.http.BunqHeader; import org.apache.commons.io.FileUtils; import org.junit.Test; @@ -37,11 +38,9 @@ private static byte[] getRequestBytes() { private static String uploadFileAndGetUuid() { HashMap customHeaders = new HashMap<>(); - customHeaders.put(ApiClient.HEADER_CONTENT_TYPE, CONTENT_TYPE); - customHeaders.put(ApiClient.HEADER_ATTACHMENT_DESCRIPTION, ATTACHMENT_DESCRIPTION); - + BunqHeader.contentType.addTo(customHeaders,CONTENT_TYPE); + BunqHeader.attachmentDescription.addTo(customHeaders,ATTACHMENT_DESCRIPTION); byte[] RequestBytes = getRequestBytes(); - return AttachmentPublic.create(customHeaders, RequestBytes).getValue(); } diff --git a/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java b/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java index bb5066b1..830fc020 100644 --- a/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java +++ b/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java @@ -4,6 +4,7 @@ import com.bunq.sdk.context.ApiContext; import com.bunq.sdk.exception.BunqException; import com.bunq.sdk.http.ApiClient; +import com.bunq.sdk.http.BunqHeader; import org.apache.commons.io.FileUtils; import org.junit.Test; @@ -54,10 +55,8 @@ public void createAvatarTest() { private String uploadAvatar(byte[] file_contents) { HashMap customHeaders = new HashMap<>(); - customHeaders.put(ApiClient.HEADER_ATTACHMENT_DESCRIPTION, ATTACHMENT_PATH_IN); - customHeaders.put(ApiClient.HEADER_CONTENT_TYPE, CONTENT_TYPE); - + BunqHeader.attachmentDescription.addTo(customHeaders,ATTACHMENT_PATH_IN); + BunqHeader.contentType.addTo(customHeaders,CONTENT_TYPE); return AttachmentPublic.create(customHeaders, file_contents).getValue(); } - } From ffb56ad6e7fb7aafa579110ae64c6663e7d75990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Sun, 17 Jun 2018 21:01:46 +0200 Subject: [PATCH 2/8] fix test on header signing (bunq/sdk_java#93) --- .../com/bunq/sdk/http/BunqBasicHeader.java | 24 +++++++-- .../com/bunq/sdk/http/BunqRequestBuilder.java | 14 ++--- .../com/bunq/sdk/security/SecurityUtils.java | 52 +++++++------------ 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index c3206eb4..247f17d7 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -2,7 +2,14 @@ import okhttp3.Response; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class BunqBasicHeader { + private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": "; + private static final String NEWLINE = "\n"; + private final BunqHeader name; private final String value; @@ -10,8 +17,8 @@ public static BunqBasicHeader get(BunqHeader header,Response response) { return new BunqBasicHeader(header,response.header(header.getHeader())); } - public BunqBasicHeader(String name, String value) { - this(BunqHeader.parse(name).get(),value); + public static Optional get(String header, String value) { + return BunqHeader.parse(header).map(h->new BunqBasicHeader(h,value)); } public BunqBasicHeader(BunqHeader name, String value) { @@ -26,4 +33,15 @@ public BunqHeader getName() { public String getValue() { return value; } -} + + private String forSigning() { + return getName().getHeader()+DELIMITER_HEADER_NAME_AND_VALUE+getValue(); + } + + public static String collectForSigning(Stream headers) { + return headers + .map(BunqBasicHeader::forSigning) + .sorted() + .collect(Collectors.joining(NEWLINE)); + } +} \ No newline at end of file diff --git a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java index 5aa2c3b1..450dd1b5 100644 --- a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java +++ b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java @@ -80,8 +80,7 @@ public BunqRequestBuilder url(URL url) { */ @Override public BunqRequestBuilder header(String name, String value) { - this.allHeader.add(new BunqBasicHeader(name, value)); - + BunqBasicHeader.get(name,value).ifPresent(this.allHeader::add); return (BunqRequestBuilder) super.header(name, value); } @@ -90,8 +89,7 @@ public BunqRequestBuilder header(String name, String value) { */ @Override public BunqRequestBuilder addHeader(String name, String value) { - this.allHeader.add(new BunqBasicHeader(name, value)); - + BunqBasicHeader.get(name,value).ifPresent(this.allHeader::add); return (BunqRequestBuilder) super.addHeader(name, value); } @@ -205,13 +203,7 @@ public BunqRequestBody getBody() { /** */ - public List getAllHeaderAsList() { + public List getAllHeader() { return this.allHeader; } - - /** - */ - public BunqBasicHeader[] getAllHeaderAsArray() { - return this.allHeader.toArray(new BunqBasicHeader[this.allHeader.size()]); - } } diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index ed42e634..7a4a7fcd 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -30,12 +30,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.*; /** * Static lib containing methods for handling encryption. @@ -127,7 +122,6 @@ public final class SecurityUtils { * Delimiter constants for building the data to sign. */ private static final String DELIMITER_METHOD_PATH = " "; - private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": "; /** * The index of the first item in an array. @@ -386,16 +380,14 @@ private static byte[] getEntityBodyBytes(BunqRequestBuilder requestBuilder) thro } private static String generateRequestHeadersSortedString(BunqRequestBuilder bunqRequestBuilder) { - return Arrays.stream(bunqRequestBuilder.getAllHeaderAsArray()) - .filter( + return BunqBasicHeader.collectForSigning(bunqRequestBuilder.getAllHeader() + .stream() + .filter( header -> header.getName().isBunq() || header.getName().equals(BunqHeader.cacheControl) || header.getName().equals(BunqHeader.userAgent) - ) - .map(header -> header.getName() + DELIMITER_HEADER_NAME_AND_VALUE + header.getValue()) - .sorted() - .collect(Collectors.joining(NEWLINE)); + )); } /** @@ -486,19 +478,14 @@ private static byte[] getResponseBytes( List allResponseHeader = new ArrayList<>(); for (int i = INDEX_FIRST; i < allHeader.names().size(); i++) { - if (BunqHeader.serverSignature.getHeader().equals(allHeader.name(i))) { - continue; + Optional header = BunqBasicHeader.get(allHeader.name(i),allHeader.get(allHeader.name(i))); + if(header.isPresent() && !BunqHeader.serverSignature.equals(header.get().getName())) { + allResponseHeader.add(header.get()); } - allResponseHeader.add(new BunqBasicHeader(allHeader.name(i),allHeader.get(allHeader.name(i)))); } try { - outputStream.write( - getResponseHeadBytes( - responseCode, - allResponseHeader.toArray(new BunqBasicHeader[allResponseHeader.size()]) - ) - ); + outputStream.write(getResponseHeadBytes(responseCode,allResponseHeader)); outputStream.write(responseBodyBytes); } catch (IOException exception) { throw new UncaughtExceptionError(exception); @@ -507,23 +494,20 @@ private static byte[] getResponseBytes( return outputStream.toByteArray(); } - private static byte[] getResponseHeadBytes(int responseCode, BunqBasicHeader[] responseHeaders) { + private static byte[] getResponseHeadBytes(int responseCode, List responseHeaders) { String requestHeadString = responseCode + NEWLINE + generateResponseHeadersSortedString(responseHeaders) + NEWLINE + NEWLINE; return requestHeadString.getBytes(); } - private static String generateResponseHeadersSortedString(BunqBasicHeader[] responseHeaders) { - return Arrays.stream(responseHeaders) - .filter( - header -> - header.getName().isBunq() && - !header.getName().equals(BunqHeader.serverSignature) - ) - .map(header -> header.getName() + DELIMITER_HEADER_NAME_AND_VALUE + header.getValue()) - .sorted() - .collect(Collectors.joining(NEWLINE)); + private static String generateResponseHeadersSortedString(List headers) { + return BunqBasicHeader.collectForSigning(headers + .stream() + .filter( + header -> + header.getName().isBunq() && + !header.getName().equals(BunqHeader.serverSignature) + )); } - } From ad67adaf991efcb3a5135278c0f3108572c4783b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Sun, 17 Jun 2018 21:23:56 +0200 Subject: [PATCH 3/8] formatting feedback (bunq/sdk_java#93) --- src/main/java/com/bunq/sdk/http/BunqBasicHeader.java | 4 ++-- src/test/java/com/bunq/sdk/http/BunqHeaderTest.java | 2 +- .../com/bunq/sdk/model/generated/endpoint/AvatarTest.java | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index 247f17d7..76ea0ea5 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -14,11 +14,11 @@ public class BunqBasicHeader { private final String value; public static BunqBasicHeader get(BunqHeader header,Response response) { - return new BunqBasicHeader(header,response.header(header.getHeader())); + return new BunqBasicHeader(header, response.header(header.getHeader())); } public static Optional get(String header, String value) { - return BunqHeader.parse(header).map(h->new BunqBasicHeader(h,value)); + return BunqHeader.parse(header).map(h -> new BunqBasicHeader(h,value)); } public BunqBasicHeader(BunqHeader name, String value) { diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java index 244e92d6..d18989c9 100644 --- a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -46,4 +46,4 @@ public void addToMap() { assertEquals("0 0 0 0 000",headers.get("X-Bunq-Geolocation")); assertEquals("test-agent",headers.get("User-Agent")); } -} \ No newline at end of file +} diff --git a/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java b/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java index 830fc020..65284c1b 100644 --- a/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java +++ b/src/test/java/com/bunq/sdk/model/generated/endpoint/AvatarTest.java @@ -54,9 +54,9 @@ public void createAvatarTest() { } private String uploadAvatar(byte[] file_contents) { - HashMap customHeaders = new HashMap<>(); - BunqHeader.attachmentDescription.addTo(customHeaders,ATTACHMENT_PATH_IN); - BunqHeader.contentType.addTo(customHeaders,CONTENT_TYPE); - return AttachmentPublic.create(customHeaders, file_contents).getValue(); + HashMap allCustomHeader = new HashMap<>(); + BunqHeader.attachmentDescription.addTo(allCustomHeader, ATTACHMENT_PATH_IN); + BunqHeader.contentType.addTo(allCustomHeader, CONTENT_TYPE); + return AttachmentPublic.create(allCustomHeader, file_contents).getValue(); } } From 4cd229c169ad4be2c44c76797210f57b8a96406c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Tue, 19 Jun 2018 09:31:22 +0200 Subject: [PATCH 4/8] formatting feedback, java7 (bunq/sdk_java#93) --- .../java/com/bunq/sdk/http/ApiClient.java | 1 + .../com/bunq/sdk/http/BunqBasicHeader.java | 7 ++-- .../java/com/bunq/sdk/http/BunqHeader.java | 38 +++++++++++++++---- .../com/bunq/sdk/http/BunqRequestBuilder.java | 14 ++++++- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/ApiClient.java b/src/main/java/com/bunq/sdk/http/ApiClient.java index 2b16eda1..e747d84a 100644 --- a/src/main/java/com/bunq/sdk/http/ApiClient.java +++ b/src/main/java/com/bunq/sdk/http/ApiClient.java @@ -285,6 +285,7 @@ private BunqResponseRaw createBunqResponseRaw(Response response) */ private static String getResponseId(Response response) { Map headerMap = getHeadersMap(response); + return BunqHeader.clientResponseId.getOrDefault(headerMap); } diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index 76ea0ea5..2236844f 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -7,6 +7,9 @@ import java.util.stream.Stream; public class BunqBasicHeader { + /** + * String format constants for signing data + */ private static final String DELIMITER_HEADER_NAME_AND_VALUE = ": "; private static final String NEWLINE = "\n"; @@ -17,10 +20,6 @@ public static BunqBasicHeader get(BunqHeader header,Response response) { return new BunqBasicHeader(header, response.header(header.getHeader())); } - public static Optional get(String header, String value) { - return BunqHeader.parse(header).map(h -> new BunqBasicHeader(h,value)); - } - public BunqBasicHeader(BunqHeader name, String value) { this.name = name; this.value = value; diff --git a/src/main/java/com/bunq/sdk/http/BunqHeader.java b/src/main/java/com/bunq/sdk/http/BunqHeader.java index 865d18f9..a54bc005 100644 --- a/src/main/java/com/bunq/sdk/http/BunqHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqHeader.java @@ -1,5 +1,6 @@ package com.bunq.sdk.http; +import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -35,8 +36,14 @@ public enum BunqHeader { this.defaultValue = defaultValue; } - public static Optional 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() { @@ -47,8 +54,12 @@ public String getDefaultValue() { return defaultValue; } + private String getOrDefault(String value) { + return value != null ? value : getDefaultValue(); + } + public void addTo(Map headers, String value) { - headers.put(getHeader(),value!=null?value:getDefaultValue()); + headers.put(getHeader(), getOrDefault(value)); } public void addTo(BunqRequestBuilder requestBuilder) { @@ -56,7 +67,7 @@ public void addTo(BunqRequestBuilder requestBuilder) { } public void addTo(BunqRequestBuilder requestBuilder, String value) { - requestBuilder.addHeader(getHeader(),value!=null?value:getDefaultValue()); + requestBuilder.addHeader(getHeader(), getOrDefault(value)); } public boolean equals(String header) { @@ -67,8 +78,21 @@ public boolean isBunq() { return getHeader().startsWith(PREFIX); } + private String findKey(Collection keys) { + for(String key:keys) { + if(this.equals(key)) { + return key; + } + } + + return null; + } + public String getOrDefault(Map headers) { - Optional key = headers.keySet().stream().filter(this::equals).findAny(); - return key.map(headers::get).orElse(getDefaultValue()); + String key = findKey(headers.keySet()); + if (key != null && headers.get(key) != null) { + return headers.get(key); + } + return getDefaultValue(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java index 450dd1b5..915023d7 100644 --- a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java +++ b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java @@ -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); } @@ -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); } From 6b906969860af5c0069a77bcc13fb4174d09eb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Tue, 19 Jun 2018 09:49:04 +0200 Subject: [PATCH 5/8] formatting feedback, java7 (bunq/sdk_java#93) --- .../com/bunq/sdk/http/BunqBasicHeader.java | 40 +++++++++++++++---- .../java/com/bunq/sdk/http/BunqHeader.java | 2 - .../com/bunq/sdk/security/SecurityUtils.java | 32 +++++++-------- .../com/bunq/sdk/http/BunqHeaderTest.java | 23 +++++++++-- 4 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index 2236844f..a73dd2ec 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -2,9 +2,10 @@ 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 { /** @@ -37,10 +38,33 @@ private String forSigning() { return getName().getHeader()+DELIMITER_HEADER_NAME_AND_VALUE+getValue(); } - public static String collectForSigning(Stream headers) { - return headers - .map(BunqBasicHeader::forSigning) - .sorted() - .collect(Collectors.joining(NEWLINE)); + public static String collectForSigning( + Collection headers, + BunqHeader exclude, + Collection includes) { + List headersForSigning = new ArrayList(); + + 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(); } } \ No newline at end of file diff --git a/src/main/java/com/bunq/sdk/http/BunqHeader.java b/src/main/java/com/bunq/sdk/http/BunqHeader.java index a54bc005..e7025429 100644 --- a/src/main/java/com/bunq/sdk/http/BunqHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqHeader.java @@ -2,8 +2,6 @@ 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"), diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index 7a4a7fcd..e5831f65 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -380,14 +380,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) + ); } /** @@ -478,9 +475,10 @@ private static byte[] getResponseBytes( List allResponseHeader = new ArrayList<>(); for (int i = INDEX_FIRST; i < allHeader.names().size(); i++) { - Optional 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)))); } } @@ -502,12 +500,10 @@ private static byte[] getResponseHeadBytes(int responseCode, List headers) { - return BunqBasicHeader.collectForSigning(headers - .stream() - .filter( - header -> - header.getName().isBunq() && - !header.getName().equals(BunqHeader.serverSignature) - )); + return BunqBasicHeader.collectForSigning( + headers, + BunqHeader.serverSignature, + Collections.emptyList() + ); } } diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java index d18989c9..bed67ba3 100644 --- a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -12,15 +12,30 @@ public class BunqHeaderTest { @Test public void parse() { // parse works case-insensitive - assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("X-Bunq-Client-Response-Id").get()); - assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("x-bunq-client-response-id").get()); + assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("X-Bunq-Client-Response-Id")); + assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("x-bunq-client-response-id")); } @Test public void isBunq() { - List nonBunqHeaders = Arrays.asList(BunqHeader.cacheControl,BunqHeader.contentType,BunqHeader.userAgent); + assertFalse(BunqHeader.cacheControl.isBunq()); + assertFalse(BunqHeader.contentType.isBunq()); + assertFalse(BunqHeader.userAgent.isBunq()); - assertEquals(nonBunqHeaders, Stream.of(BunqHeader.values()).filter(h->!h.isBunq()).collect(Collectors.toList())); + assertTrue(BunqHeader.attachmentDescription.isBunq()); + assertTrue(BunqHeader.clientAuthentication.isBunq()); + assertTrue(BunqHeader.clientEncryptionHMAC.isBunq()); + assertTrue(BunqHeader.clientEncryptionIV.isBunq()); + assertTrue(BunqHeader.clientEncryptionIV.isBunq()); + assertTrue(BunqHeader.clientEncryptionKey.isBunq()); + assertTrue(BunqHeader.clientRequestId.isBunq()); + assertTrue(BunqHeader.clientSignature.isBunq()); + assertTrue(BunqHeader.clientResponseId.isBunq()); + assertTrue(BunqHeader.geolocation.isBunq()); + assertTrue(BunqHeader.region.isBunq()); + assertTrue(BunqHeader.serverSignature.isBunq()); + assertTrue(BunqHeader.clientEncryptionKey.isBunq()); + assertTrue(BunqHeader.clientRequestId.isBunq()); } @Test From 30d43ee750e41f8bb2008298c0b70aa83bcd0168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Tue, 19 Jun 2018 10:00:09 +0200 Subject: [PATCH 6/8] formatting feedback, java7 (bunq/sdk_java#93) --- src/main/java/com/bunq/sdk/http/BunqHeader.java | 14 +++++++------- .../java/com/bunq/sdk/http/BunqRequestBuilder.java | 4 ++-- .../java/com/bunq/sdk/security/SecurityUtils.java | 4 ++-- .../java/com/bunq/sdk/http/BunqHeaderTest.java | 2 -- .../generated/endpoint/AttachmentPublicTest.java | 12 +++++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/BunqHeader.java b/src/main/java/com/bunq/sdk/http/BunqHeader.java index e7025429..5ab93ecc 100644 --- a/src/main/java/com/bunq/sdk/http/BunqHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqHeader.java @@ -13,12 +13,12 @@ public enum BunqHeader { 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-"; @@ -77,8 +77,8 @@ public boolean isBunq() { } private String findKey(Collection keys) { - for(String key:keys) { - if(this.equals(key)) { + for (String key:keys) { + if (this.equals(key)) { return key; } } diff --git a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java index 915023d7..d89ed3cb 100644 --- a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java +++ b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java @@ -88,7 +88,7 @@ private void addToAllHeader(String name,String value) { */ @Override public BunqRequestBuilder header(String name, String value) { - addToAllHeader(name,value); + addToAllHeader(name, value); return (BunqRequestBuilder) super.header(name, value); } @@ -98,7 +98,7 @@ public BunqRequestBuilder header(String name, String value) { */ @Override public BunqRequestBuilder addHeader(String name, String value) { - addToAllHeader(name,value); + addToAllHeader(name, value); return (BunqRequestBuilder) super.addHeader(name, value); } diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index e5831f65..1e7f08d0 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -459,9 +459,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); } diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java index bed67ba3..e1e054d8 100644 --- a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -3,8 +3,6 @@ import org.junit.Test; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.junit.Assert.*; diff --git a/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java b/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java index 48eca29f..866d34d2 100644 --- a/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java +++ b/src/test/java/com/bunq/sdk/model/generated/endpoint/AttachmentPublicTest.java @@ -10,6 +10,7 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; +import java.util.Map; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -37,11 +38,12 @@ private static byte[] getRequestBytes() { } private static String uploadFileAndGetUuid() { - HashMap customHeaders = new HashMap<>(); - BunqHeader.contentType.addTo(customHeaders,CONTENT_TYPE); - BunqHeader.attachmentDescription.addTo(customHeaders,ATTACHMENT_DESCRIPTION); - byte[] RequestBytes = getRequestBytes(); - return AttachmentPublic.create(customHeaders, RequestBytes).getValue(); + Map customHeaders = new HashMap<>(); + + BunqHeader.contentType.addTo(customHeaders, CONTENT_TYPE); + BunqHeader.attachmentDescription.addTo(customHeaders, ATTACHMENT_DESCRIPTION); + + return AttachmentPublic.create(customHeaders, getRequestBytes()).getValue(); } /** From abb8cb6f7a1a1c0bc95a9a94eb4c31091fae427c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Tue, 19 Jun 2018 10:27:11 +0200 Subject: [PATCH 7/8] formatting feedback, java7 (bunq/sdk_java#93) --- .../com/bunq/sdk/security/SecurityUtils.java | 6 ++--- .../com/bunq/sdk/http/BunqHeaderTest.java | 24 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index 1e7f08d0..a45a0bf2 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -284,7 +284,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()); } @@ -293,7 +293,7 @@ private static void addHeaderClientEncryptionKey(ApiContext apiContext, SecretKe private static void addHeaderClientEncryptionIv(byte[] initializationVector, Map 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, @@ -326,7 +326,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()); } diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java index e1e054d8..748fa413 100644 --- a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -10,8 +10,8 @@ public class BunqHeaderTest { @Test public void parse() { // parse works case-insensitive - assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("X-Bunq-Client-Response-Id")); - assertEquals(BunqHeader.clientResponseId,BunqHeader.parse("x-bunq-client-response-id")); + assertEquals(BunqHeader.clientResponseId, BunqHeader.parse("X-Bunq-Client-Response-Id")); + assertEquals(BunqHeader.clientResponseId, BunqHeader.parse("x-bunq-client-response-id")); } @Test @@ -40,23 +40,23 @@ public void isBunq() { public void getOrDefault() { BunqHeader h = BunqHeader.clientResponseId; - assertEquals("test-id",h.getOrDefault(Collections.singletonMap("x-bunq-client-response-id","test-id"))); - assertEquals("Could not determine response id.",h.getOrDefault(Collections.singletonMap("x-bunq-some-other-header","test-id"))); - assertEquals("Could not determine response id.",h.getOrDefault(Collections.emptyMap())); + assertEquals("test-id", h.getOrDefault(Collections.singletonMap("x-bunq-client-response-id", "test-id"))); + assertEquals("Could not determine response id.", h.getOrDefault(Collections.singletonMap("x-bunq-some-other-header", "test-id"))); + assertEquals("Could not determine response id.", h.getOrDefault(Collections.emptyMap())); } @Test public void addToMap() { - Map headers = new HashMap<>(); + Map headers = new HashMap<>(); //sut - BunqHeader.language.addTo(headers,null); - BunqHeader.geolocation.addTo(headers,null); - BunqHeader.userAgent.addTo(headers,"test-agent"); + BunqHeader.language.addTo(headers, null); + BunqHeader.geolocation.addTo(headers, null); + BunqHeader.userAgent.addTo(headers, "test-agent"); // verify - assertEquals("en_US",headers.get("X-Bunq-Language")); - assertEquals("0 0 0 0 000",headers.get("X-Bunq-Geolocation")); - assertEquals("test-agent",headers.get("User-Agent")); + assertEquals("en_US", headers.get("X-Bunq-Language")); + assertEquals("0 0 0 0 000", headers.get("X-Bunq-Geolocation")); + assertEquals("test-agent", headers.get("User-Agent")); } } From 0ebd723336d6b070451ba6399bdf12272574de77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20van=20de=20Giessen?= Date: Tue, 19 Jun 2018 19:46:11 +0200 Subject: [PATCH 8/8] formatting feedback (bunq/sdk_java#93) --- .../java/com/bunq/sdk/http/ApiClient.java | 6 ++--- .../com/bunq/sdk/http/BunqBasicHeader.java | 6 ++--- .../java/com/bunq/sdk/http/BunqHeader.java | 16 +++++++----- .../com/bunq/sdk/http/BunqRequestBuilder.java | 2 +- .../com/bunq/sdk/security/SecurityUtils.java | 26 ++++++++++++------- .../com/bunq/sdk/http/BunqHeaderTest.java | 19 +++++++++----- 6 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/bunq/sdk/http/ApiClient.java b/src/main/java/com/bunq/sdk/http/ApiClient.java index e747d84a..7ed201b9 100644 --- a/src/main/java/com/bunq/sdk/http/ApiClient.java +++ b/src/main/java/com/bunq/sdk/http/ApiClient.java @@ -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); } @@ -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)); } } diff --git a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java index a73dd2ec..b2672c7c 100644 --- a/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqBasicHeader.java @@ -17,7 +17,7 @@ public class BunqBasicHeader { private final BunqHeader name; private final String value; - public static BunqBasicHeader get(BunqHeader header,Response response) { + public static BunqBasicHeader get(BunqHeader header, Response response) { return new BunqBasicHeader(header, response.header(header.getHeader())); } @@ -35,7 +35,7 @@ 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( @@ -67,4 +67,4 @@ public static String collectForSigning( return stringBuffer.toString(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/bunq/sdk/http/BunqHeader.java b/src/main/java/com/bunq/sdk/http/BunqHeader.java index 5ab93ecc..519df850 100644 --- a/src/main/java/com/bunq/sdk/http/BunqHeader.java +++ b/src/main/java/com/bunq/sdk/http/BunqHeader.java @@ -5,7 +5,7 @@ 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"), @@ -26,7 +26,7 @@ public enum BunqHeader { private final String defaultValue; BunqHeader(String header) { - this(header,null); + this(header, null); } BunqHeader(String header, String defaultValue) { @@ -53,15 +53,19 @@ public String getDefaultValue() { } private String getOrDefault(String value) { - return value != null ? value : getDefaultValue(); + if (value != null) { + return value; + } + + return getDefaultValue(); } - public void addTo(Map headers, String value) { + public void addTo(Map 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) { @@ -86,7 +90,7 @@ private String findKey(Collection keys) { return null; } - public String getOrDefault(Map headers) { + public String getOrDefault(Map headers) { String key = findKey(headers.keySet()); if (key != null && headers.get(key) != null) { return headers.get(key); diff --git a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java index d89ed3cb..a52dd82c 100644 --- a/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java +++ b/src/main/java/com/bunq/sdk/http/BunqRequestBuilder.java @@ -75,7 +75,7 @@ public BunqRequestBuilder url(URL url) { return (BunqRequestBuilder) super.url(url); } - private void addToAllHeader(String name,String value) { + private void addToAllHeader(String name, String value) { BunqHeader header = BunqHeader.parse(name); if (header != null) { diff --git a/src/main/java/com/bunq/sdk/security/SecurityUtils.java b/src/main/java/com/bunq/sdk/security/SecurityUtils.java index a45a0bf2..484ce31d 100644 --- a/src/main/java/com/bunq/sdk/security/SecurityUtils.java +++ b/src/main/java/com/bunq/sdk/security/SecurityUtils.java @@ -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; @@ -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. @@ -383,7 +391,7 @@ private static String generateRequestHeadersSortedString(BunqRequestBuilder bunq return BunqBasicHeader.collectForSigning( bunqRequestBuilder.getAllHeader(), null, - Arrays.asList(BunqHeader.cacheControl,BunqHeader.userAgent) + Arrays.asList(BunqHeader.cacheControl, BunqHeader.userAgent) ); } @@ -459,7 +467,7 @@ public static void validateResponseSignature( response.headers() ); Signature signature = getSignatureInstance(); - BunqBasicHeader serverSignature = BunqBasicHeader.get(BunqHeader.serverSignature,response); + BunqBasicHeader serverSignature = BunqBasicHeader.get(BunqHeader.serverSignature, response); byte[] serverSignatureBase64Bytes = serverSignature.getValue().getBytes(); byte[] serverSignatureDecoded = Base64.getDecoder().decode(serverSignatureBase64Bytes); @@ -478,12 +486,12 @@ private static byte[] getResponseBytes( BunqHeader header = BunqHeader.parse(allHeader.name(i)); if (header != null && !BunqHeader.serverSignature.equals(header)) { - allResponseHeader.add(new BunqBasicHeader(header,allHeader.get(allHeader.name(i)))); + 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); @@ -492,9 +500,9 @@ private static byte[] getResponseBytes( return outputStream.toByteArray(); } - private static byte[] getResponseHeadBytes(int responseCode, List responseHeaders) { - String requestHeadString = responseCode + NEWLINE + - generateResponseHeadersSortedString(responseHeaders) + NEWLINE + NEWLINE; + private static byte[] getResponseHeadBytes(int code, List headers) { + String requestHeadString = code + NEWLINE + + generateResponseHeadersSortedString(headers) + NEWLINE + NEWLINE; return requestHeadString.getBytes(); } diff --git a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java index 748fa413..ddaf0c78 100644 --- a/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java +++ b/src/test/java/com/bunq/sdk/http/BunqHeaderTest.java @@ -1,10 +1,14 @@ package com.bunq.sdk.http; -import org.junit.Test; +import java.util.Collections; +import java.util.Map; +import java.util.HashMap; -import java.util.*; +import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class BunqHeaderTest { @Test @@ -40,9 +44,12 @@ public void isBunq() { public void getOrDefault() { BunqHeader h = BunqHeader.clientResponseId; - assertEquals("test-id", h.getOrDefault(Collections.singletonMap("x-bunq-client-response-id", "test-id"))); - assertEquals("Could not determine response id.", h.getOrDefault(Collections.singletonMap("x-bunq-some-other-header", "test-id"))); - assertEquals("Could not determine response id.", h.getOrDefault(Collections.emptyMap())); + assertEquals("test-id", + h.getOrDefault(Collections.singletonMap("x-bunq-client-response-id", "test-id"))); + assertEquals("Could not determine response id.", + h.getOrDefault(Collections.singletonMap("x-bunq-some-other-header", "test-id"))); + assertEquals("Could not determine response id.", + h.getOrDefault(Collections.emptyMap())); } @Test