diff --git a/src/main/java/com/uid2/operator/service/V2RequestUtil.java b/src/main/java/com/uid2/operator/service/V2RequestUtil.java index c19fc70db..19c45ca56 100644 --- a/src/main/java/com/uid2/operator/service/V2RequestUtil.java +++ b/src/main/java/com/uid2/operator/service/V2RequestUtil.java @@ -51,6 +51,14 @@ public boolean isValid() { private static final byte VERSION = 1; + // Appended to request-envelope parse errors to help callers who send an unencrypted body (e.g. a raw + // curl request with base64-encoded JSON) understand that the body must be an encrypted request envelope. + static final String ENCRYPTION_HINT = " The request body must be an encrypted request envelope, not plain or" + + " base64-encoded JSON. If you are calling this endpoint directly (for example with curl), base64-encoding" + + " the JSON is not enough. See" + + " https://unifiedid.com/docs/getting-started/gs-encryption-decryption#encryption-and-decryption-code-examples" + + " for payload encryption and response decryption code examples."; + public static final int V2_REFRESH_PAYLOAD_LENGTH = 388; public static final long V2_REQUEST_TIMESTAMP_DRIFT_THRESHOLD_IN_MINUTES = 1; @@ -119,18 +127,18 @@ private static V2Request parseRequestCommon(byte[] bodyBytes, ClientKey ck, IClo } if (bodyBytes.length < MIN_PAYLOAD_LENGTH) { - return new V2Request("Invalid body: Body too short. Check encryption method."); + return new V2Request("Invalid body: Body too short. Check encryption method." + ENCRYPTION_HINT); } if (bodyBytes[0] != VERSION) { - return new V2Request("Invalid body: Version mismatch."); + return new V2Request("Invalid body: Version mismatch." + ENCRYPTION_HINT); } byte[] decryptedBody; try { decryptedBody = AesGcm.decrypt(bodyBytes, 1, ck.getSecretBytes()); } catch (Exception ex) { - return new V2Request("Invalid body: Check encryption key (ClientSecret)"); + return new V2Request("Invalid body: Check encryption key (ClientSecret)" + ENCRYPTION_HINT); } // Request envelop format: diff --git a/src/test/java/com/uid2/operator/V2RequestUtilTest.java b/src/test/java/com/uid2/operator/V2RequestUtilTest.java index d08b52389..71b6c2a86 100644 --- a/src/test/java/com/uid2/operator/V2RequestUtilTest.java +++ b/src/test/java/com/uid2/operator/V2RequestUtilTest.java @@ -120,7 +120,24 @@ public void testParseRequestWithTooShortBody() { V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString("dGVzdA==", null, clock); - assertEquals("Invalid body: Body too short. Check encryption method.", res.errorMessage); + assertThat(res.errorMessage).startsWith("Invalid body: Body too short. Check encryption method."); + assertThat(res.errorMessage).contains("gs-encryption-decryption"); + } + + @Test + public void testParseRequestWithVersionMismatch() { + when(clock.now()).thenReturn(MOCK_NOW); + + // Base64 of plain (unencrypted) JSON long enough to pass the length check but whose first byte + // is not the expected envelope version byte - this is what a raw curl-with-base64 request produces. + String plainJsonBase64 = java.util.Base64.getEncoder().encodeToString( + "{\"email_hash\":\"tMmiiTI7IaAcPpQPFQ65uMVCWH8av9jw4cwf/F5HVRQ=\",\"version\":2}" + .getBytes(java.nio.charset.StandardCharsets.UTF_8)); + + V2RequestUtil.V2Request res = V2RequestUtil.parseRequestAsString(plainJsonBase64, null, clock); + + assertThat(res.errorMessage).startsWith("Invalid body: Version mismatch."); + assertThat(res.errorMessage).contains("gs-encryption-decryption"); } @Test