diff --git a/src/main/java/com/mindee/parsing/BaseLocalResponse.java b/src/main/java/com/mindee/parsing/BaseLocalResponse.java index 3284e9984..6d5b5e14d 100644 --- a/src/main/java/com/mindee/parsing/BaseLocalResponse.java +++ b/src/main/java/com/mindee/parsing/BaseLocalResponse.java @@ -9,6 +9,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.InvalidKeyException; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -99,10 +100,24 @@ public String getHmacSignature(String secretKey) { * Verify that the payload's signature matches the one received from the server. * * @param secretKey Your secret key from the Mindee platform. - * @param signature The signature from the "X-Mindee-Hmac-Signature" HTTP header. + * @param signature The signature from the "X-Signature" HTTP header. * @return true if the signatures match. */ public boolean isValidHmacSignature(String secretKey, String signature) { - return signature.equals(getHmacSignature(secretKey)); + if (signature == null || secretKey == null) { + return false; + } + + String expectedSignature = getHmacSignature(secretKey); + if (expectedSignature.isEmpty()) { + return false; + } + + byte[] expectedBytes = expectedSignature.getBytes(StandardCharsets.UTF_8); + byte[] actualBytes = signature + .toLowerCase(java.util.Locale.ROOT) + .getBytes(StandardCharsets.UTF_8); + + return MessageDigest.isEqual(expectedBytes, actualBytes); } } diff --git a/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java b/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java index 981fb194b..fbfb2d8f5 100644 --- a/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java +++ b/src/test/java/com/mindee/v1/parsing/LocalResponseTest.java @@ -12,8 +12,10 @@ import java.nio.file.Files; import java.nio.file.Path; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +@DisplayName("MindeeV1 – Load Local Response") public class LocalResponseTest { /** * Fake secret key. diff --git a/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java b/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java index ad59a14e3..19d2cc8fb 100644 --- a/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java +++ b/src/test/java/com/mindee/v2/parsing/LocalResponseTest.java @@ -2,31 +2,43 @@ import static com.mindee.TestingUtilities.getResourcePath; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.mindee.MindeeException; import com.mindee.v2.product.extraction.ExtractionResponse; import java.io.IOException; -import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +@DisplayName("MindeeV2 – Load Local Response") public class LocalResponseTest { - @Test - void loadDocument_withPath_mustReturnValidLocalResponse() throws IOException { - var localResponse = new LocalResponse( - getResourcePath("v2/products/extraction/financial_document/complete.json") - ); - ExtractionResponse loaded = localResponse.deserializeResponse(ExtractionResponse.class); + private static final String SIGNATURE = "79dd6572f8a97822fb12f2f72bc84ecdc7c968dede712cf23a256ac3eac593d4"; + private static final String DUMMY_SECRET_KEY = "ogNjY44MhvKPGTtVsI8zG82JqWQa68woYQH"; + + private static void assertLocalResponse(LocalResponse localResponse) { + assertEquals(SIGNATURE, localResponse.getHmacSignature(DUMMY_SECRET_KEY)); - assertNotNull(loaded, "Loaded InferenceResponse must not be null"); + assertFalse(localResponse.isValidHmacSignature(DUMMY_SECRET_KEY, "invalid signature")); + assertFalse(localResponse.isValidHmacSignature(DUMMY_SECRET_KEY, null)); + assertFalse(localResponse.isValidHmacSignature(null, SIGNATURE)); + assertFalse(localResponse.isValidHmacSignature(null, null)); + assertFalse(localResponse.isValidHmacSignature(DUMMY_SECRET_KEY, "")); + assertTrue(localResponse.isValidHmacSignature(DUMMY_SECRET_KEY, SIGNATURE)); + assertTrue(localResponse.isValidHmacSignature(DUMMY_SECRET_KEY, SIGNATURE.toUpperCase())); + + ExtractionResponse response = localResponse.deserializeResponse(ExtractionResponse.class); + assertNotNull(response, "Loaded ExtractionResponse must not be null"); assertEquals( "12345678-1234-1234-1234-123456789abc", - loaded.getInference().getModel().getId(), + response.getInference().getModel().getId(), "Model Id mismatch" ); assertEquals( "John Smith", - loaded + response .getInference() .getResult() .getFields() @@ -37,14 +49,21 @@ void loadDocument_withPath_mustReturnValidLocalResponse() throws IOException { ); } + @Test + void loadDocument_withPath_mustReturnValidLocalResponse() throws IOException { + var localResponse = new LocalResponse( + getResourcePath("v2/products/extraction/financial_document/complete.json") + ); + assertLocalResponse(localResponse); + } + @Test void givenInvalidJsonInput_shouldThrow() { var localResponse = new LocalResponse("{invalid json"); - var err = Assertions - .assertThrows( - MindeeException.class, - () -> localResponse.deserializeResponse(ExtractionResponse.class) - ); - Assertions.assertEquals("Invalid JSON payload.", err.getMessage()); + var err = assertThrows( + MindeeException.class, + () -> localResponse.deserializeResponse(ExtractionResponse.class) + ); + assertEquals("Invalid JSON payload.", err.getMessage()); } }