Skip to content

Commit 22f7bc3

Browse files
authored
Merge pull request #83 from IABTechLab/aul-UID2-5485-identity-map-v3
Identity Map V3
2 parents 5aa62a5 + 43ddf4d commit 22f7bc3

16 files changed

+928
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ dependencies/
88
build/**
99
.DS_Store
1010
*/node_modules/*
11+
.env

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.uid2</groupId>
88
<artifactId>uid2-client</artifactId>
9-
<version>4.6.0</version>
9+
<version>4.6.8-alpha-29-SNAPSHOT</version>
1010

1111
<name>${project.groupId}:${project.artifactId}</name>
1212
<description>UID2 Client</description>

src/main/java/com/uid2/client/EnvelopeV2.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22

33

44
public class EnvelopeV2 {
5-
EnvelopeV2(String envelope, byte[] nonce) {
6-
this.envelope = envelope;
5+
EnvelopeV2(byte[] envelope, byte[] nonce) {
6+
this.binaryEnvelope = envelope;
77
this.nonce = nonce;
88
}
99

1010
/**
1111
* @return an encrypted request envelope which can be used in the POST body of a <a href="https://unifiedid.com/docs/endpoints/summary-endpoints">UID2 endpoint</a>.
1212
* See <a href="https://unifiedid.com/docs/getting-started/gs-encryption-decryption#encrypted-request-envelope">Encrypted Request Envelope</a>
1313
*/
14-
public String getEnvelope() { return envelope; }
14+
public String getEnvelope() { return InputUtil.byteArrayToBase64(binaryEnvelope); }
1515
byte[] getNonce() { return nonce;}
1616

17-
private final String envelope;
17+
public byte[] getBinaryEnvelope() {
18+
return binaryEnvelope;
19+
}
20+
21+
private final byte[] binaryEnvelope;
1822
private final byte[] nonce;
1923
}
2024

src/main/java/com/uid2/client/IdentityMapClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public IdentityMapClient(String uid2BaseUrl, String clientApiKey, String base64S
1919
public IdentityMapResponse generateIdentityMap(IdentityMapInput identityMapInput) {
2020
EnvelopeV2 envelope = identityMapHelper.createEnvelopeForIdentityMapRequest(identityMapInput);
2121

22-
String responseString = uid2ClientHelper.makeRequest(envelope, "/v2/identity/map");
22+
String responseString = uid2ClientHelper.makeRequest("/v2/identity/map", envelope).getAsString();
2323
return identityMapHelper.createIdentityMapResponse(responseString, envelope, identityMapInput);
2424
}
2525

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.uid2.client;
2+
3+
public class IdentityMapV3Client {
4+
/**
5+
* @param uid2BaseUrl The <a href="https://unifiedid.com/docs/getting-started/gs-environments">UID2 Base URL</a>
6+
* @param clientApiKey Your client API key
7+
* @param base64SecretKey Your client secret key
8+
*/
9+
public IdentityMapV3Client(String uid2BaseUrl, String clientApiKey, String base64SecretKey) {
10+
identityMapHelper = new IdentityMapV3Helper(base64SecretKey);
11+
uid2ClientHelper = new Uid2ClientHelper(uid2BaseUrl, clientApiKey);
12+
}
13+
14+
/**
15+
* @param identityMapInput represents the input required for <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a>
16+
* @return an IdentityMapV3Response instance
17+
* @throws Uid2Exception if the response did not contain a "success" status, or the response code was not 200, or there was an error communicating with the provided UID2 Base URL
18+
*/
19+
public IdentityMapV3Response generateIdentityMap(IdentityMapV3Input identityMapInput) {
20+
EnvelopeV2 envelope = identityMapHelper.createEnvelopeForIdentityMapRequest(identityMapInput);
21+
22+
Uid2Response response = uid2ClientHelper.makeBinaryRequest("/v3/identity/map", envelope);
23+
if (response.isBinary()) {
24+
return identityMapHelper.createIdentityMapResponse(response.getAsBytes(), envelope, identityMapInput);
25+
} else {
26+
return identityMapHelper.createIdentityMapResponse(response.getAsString(), envelope, identityMapInput);
27+
}
28+
}
29+
30+
private final IdentityMapV3Helper identityMapHelper;
31+
private final Uid2ClientHelper uid2ClientHelper;
32+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.uid2.client;
2+
3+
import com.google.gson.Gson;
4+
5+
import java.nio.charset.StandardCharsets;
6+
7+
public class IdentityMapV3Helper {
8+
/**
9+
* @param base64SecretKey your UID2 client secret
10+
*/
11+
public IdentityMapV3Helper(String base64SecretKey) {uid2Helper = new Uid2Helper(base64SecretKey);}
12+
13+
/**
14+
* @param identityMapInput represents the input required for <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a>
15+
* @return an EnvelopeV2 instance to use in the POST body of <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a>
16+
*/
17+
public EnvelopeV2 createEnvelopeForIdentityMapRequest(IdentityMapV3Input identityMapInput) {
18+
byte[] jsonBytes = new Gson().toJson(identityMapInput).getBytes(StandardCharsets.UTF_8);
19+
return uid2Helper.createEnvelopeV2(jsonBytes);
20+
}
21+
22+
23+
/**
24+
* @param responseString the response body returned by a call to <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a>
25+
* @param envelope the EnvelopeV2 instance returned by {@link #createEnvelopeForIdentityMapRequest}
26+
* @param identityMapInput the same instance that was passed to {@link #createEnvelopeForIdentityMapRequest}.
27+
* @return an IdentityMapV3Response instance
28+
*/
29+
public IdentityMapV3Response createIdentityMapResponse(String responseString, EnvelopeV2 envelope, IdentityMapV3Input identityMapInput) {
30+
String decryptedResponseString = uid2Helper.decrypt(responseString, envelope.getNonce());
31+
return new IdentityMapV3Response(decryptedResponseString, identityMapInput);
32+
}
33+
34+
public IdentityMapV3Response createIdentityMapResponse(byte[] response, EnvelopeV2 envelope, IdentityMapV3Input identityMapInput) {
35+
String decryptedResponseString = uid2Helper.decrypt(response, envelope.getNonce());
36+
return new IdentityMapV3Response(decryptedResponseString, identityMapInput);
37+
}
38+
39+
private final Uid2Helper uid2Helper;
40+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package com.uid2.client;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
5+
import java.util.*;
6+
7+
public class IdentityMapV3Input {
8+
/**
9+
* @param emails a list of normalized or unnormalized email addresses
10+
* @return a IdentityMapV3Input instance, to be used in {@link IdentityMapV3Helper#createEnvelopeForIdentityMapRequest}
11+
*/
12+
public static IdentityMapV3Input fromEmails(List<String> emails) {
13+
return new IdentityMapV3Input().withEmails(emails);
14+
}
15+
16+
/**
17+
* @param hashedEmails a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-hash-encoding">hashed</a> email address
18+
* @return an IdentityMapV3Input instance
19+
*/
20+
public static IdentityMapV3Input fromHashedEmails(List<String> hashedEmails) {
21+
return new IdentityMapV3Input().withHashedEmails(hashedEmails);
22+
}
23+
24+
/**
25+
* @param phones a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> phone number
26+
* @return an IdentityMapV3Input instance
27+
*/
28+
public static IdentityMapV3Input fromPhones(List<String> phones) {
29+
return new IdentityMapV3Input().withPhones(phones);
30+
}
31+
32+
/**
33+
* @param hashedPhones a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-hash-encoding">hashed</a> phone number
34+
* @return an IdentityMapV3Input instance
35+
*/
36+
public static IdentityMapV3Input fromHashedPhones(List<String> hashedPhones) {
37+
return new IdentityMapV3Input().withHashedPhones(hashedPhones);
38+
}
39+
40+
// Transient as this should not be part of the serialized JSON payload we send to UID2 Operator
41+
private transient final Map<String, List<String>> hashedDiiToRawDii = new HashMap<>();
42+
43+
@SerializedName("email_hash")
44+
private final List<String> hashedEmails = new ArrayList<>();
45+
46+
@SerializedName("phone_hash")
47+
private final List<String> hashedPhones = new ArrayList<>();
48+
49+
// We never send unhashed emails or phone numbers in the SDK, but they are required fields in the API request
50+
@SerializedName("email")
51+
private List<String> emails = Collections.unmodifiableList(new ArrayList<>());
52+
@SerializedName("phone")
53+
private List<String> phones = Collections.unmodifiableList(new ArrayList<>());
54+
55+
public IdentityMapV3Input() {}
56+
57+
/**
58+
* @param hashedEmails a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-hash-encoding">hashed</a> email address
59+
* @return this IdentityMapV3Input instance
60+
*/
61+
public IdentityMapV3Input withHashedEmails(List<String> hashedEmails) {
62+
for (String hashedEmail : hashedEmails) {
63+
withHashedEmail(hashedEmail);
64+
}
65+
return this;
66+
}
67+
68+
/**
69+
* @param hashedEmail a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#email-address-hash-encoding">hashed</a> email address
70+
* @return this IdentityMapV3Input instance
71+
*/
72+
public IdentityMapV3Input withHashedEmail(String hashedEmail) {
73+
this.hashedEmails.add(hashedEmail);
74+
addToDiiMappings(hashedEmail, hashedEmail);
75+
return this;
76+
}
77+
78+
/**
79+
* @param hashedPhones a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-hash-encoding">hashed</a> phone number
80+
* @return this IdentityMapV3Input instance
81+
*/
82+
public IdentityMapV3Input withHashedPhones(List<String> hashedPhones) {
83+
for (String hashedPhone : hashedPhones) {
84+
withHashedPhone(hashedPhone);
85+
}
86+
return this;
87+
}
88+
89+
/**
90+
* @param hashedPhone a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> and <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-hash-encoding">hashed</a> phone number
91+
* @return this IdentityMapV3Input instance
92+
*/
93+
public IdentityMapV3Input withHashedPhone(String hashedPhone) {
94+
this.hashedPhones.add(hashedPhone);
95+
addToDiiMappings(hashedPhone, hashedPhone);
96+
return this;
97+
}
98+
99+
/**
100+
* @param emails a list of normalized or unnormalized email addresses
101+
* @return this IdentityMapV3Input instance
102+
*/
103+
public IdentityMapV3Input withEmails(List<String> emails) {
104+
for (String email : emails) {
105+
withEmail(email);
106+
}
107+
return this;
108+
}
109+
110+
/**
111+
* @param email a normalized or unnormalized email address
112+
* @return this IdentityMapV3Input instance
113+
*/
114+
public IdentityMapV3Input withEmail(String email) {
115+
String hashedEmail = InputUtil.normalizeAndHashEmail(email);
116+
this.hashedEmails.add(hashedEmail);
117+
addToDiiMappings(hashedEmail, email);
118+
return this;
119+
}
120+
121+
/**
122+
* @param phones a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> phone number
123+
* @return this IdentityMapV3Input instance
124+
*/
125+
public IdentityMapV3Input withPhones(List<String> phones) {
126+
for (String phone : phones) {
127+
withPhone(phone);
128+
}
129+
return this;
130+
}
131+
132+
/**
133+
* @param phone a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> phone number
134+
* @return this IdentityMapV3Input instance
135+
*/
136+
public IdentityMapV3Input withPhone(String phone) {
137+
if (!InputUtil.isPhoneNumberNormalized(phone)) {
138+
throw new IllegalArgumentException("phone number is not normalized: " + phone);
139+
}
140+
141+
String hashedPhone = InputUtil.getBase64EncodedHash(phone);
142+
this.hashedPhones.add(hashedPhone);
143+
addToDiiMappings(hashedPhone, phone);
144+
return this;
145+
}
146+
147+
List<String> getInputDiis(String identityType, int i) {
148+
return hashedDiiToRawDii.get(getHashedDii(identityType, i));
149+
}
150+
151+
private void addToDiiMappings(String hashedDii, String rawDii) {
152+
hashedDiiToRawDii.computeIfAbsent(hashedDii, k -> new ArrayList<>()).add(rawDii);
153+
}
154+
155+
private String getHashedDii(String identityType, int i) {
156+
switch (identityType) {
157+
case "email_hash": return hashedEmails.get(i);
158+
case "phone_hash": return hashedPhones.get(i);
159+
}
160+
throw new Uid2Exception("Unexpected identity type: " + identityType);
161+
}
162+
}

0 commit comments

Comments
 (0)