-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
advertiser and data provider support #55
Changes from all commits
12e4101
7c71fef
7d53c9c
4ee5e7f
865c1b3
f84fb01
1a90521
b490575
6b0b14e
0ca1fef
803bb0c
5d414e9
bc1c3dc
a067a82
55e22d9
1eb4ec0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.uid2.client; | ||
|
||
public class IdentityMapClient { | ||
/** | ||
* @param uid2BaseUrl The <a href="https://unifiedid.com/docs/getting-started/gs-environments">UID2 Base URL</a> | ||
* @param clientApiKey Your client API key | ||
* @param base64SecretKey Your client secret key | ||
*/ | ||
public IdentityMapClient(String uid2BaseUrl, String clientApiKey, String base64SecretKey) { | ||
identityMapHelper = new IdentityMapHelper(base64SecretKey); | ||
uid2ClientHelper = new Uid2ClientHelper(uid2BaseUrl, clientApiKey); | ||
} | ||
|
||
/** | ||
* @param identityMapInput represents the input required for <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a> | ||
* @return an IdentityMapResponse instance | ||
* @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 | ||
*/ | ||
public IdentityMapResponse generateIdentityMap(IdentityMapInput identityMapInput) { | ||
EnvelopeV2 envelope = identityMapHelper.createEnvelopeForIdentityMapRequest(identityMapInput); | ||
|
||
String responseString = uid2ClientHelper.makeRequest(envelope, "/v2/identity/map"); | ||
return identityMapHelper.createIdentityMapResponse(responseString, envelope, identityMapInput); | ||
} | ||
|
||
private final IdentityMapHelper identityMapHelper; | ||
private final Uid2ClientHelper uid2ClientHelper; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.uid2.client; | ||
|
||
import com.google.gson.Gson; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
|
||
public class IdentityMapHelper { | ||
/** | ||
* @param base64SecretKey your UID2 client secret | ||
*/ | ||
public IdentityMapHelper(String base64SecretKey) {uid2Helper = new Uid2Helper(base64SecretKey);} | ||
|
||
/** | ||
* @param identityMapInput represents the input required for <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a> | ||
* @return an EnvelopeV2 instance to use in the POST body of <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a> | ||
*/ | ||
public EnvelopeV2 createEnvelopeForIdentityMapRequest(IdentityMapInput identityMapInput) { | ||
byte[] jsonBytes = new Gson().toJson(identityMapInput).getBytes(StandardCharsets.UTF_8); | ||
return uid2Helper.createEnvelopeV2(jsonBytes); | ||
} | ||
|
||
|
||
/** | ||
* @param responseString the response body returned by a call to <a href="https://unifiedid.com/docs/endpoints/post-identity-map">/identity/map</a> | ||
* @param envelope the EnvelopeV2 instance returned by {@link #createEnvelopeForIdentityMapRequest} | ||
* @param identityMapInput the same instance that was passed to {@link #createEnvelopeForIdentityMapRequest}. | ||
* @return an IdentityMapResponse instance | ||
*/ | ||
public IdentityMapResponse createIdentityMapResponse(String responseString, EnvelopeV2 envelope, IdentityMapInput identityMapInput) { | ||
String decryptedResponseString = uid2Helper.decrypt(responseString, envelope.getNonce()); | ||
return new IdentityMapResponse(decryptedResponseString, identityMapInput); | ||
} | ||
|
||
Uid2Helper uid2Helper; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.uid2.client; | ||
|
||
import com.google.gson.annotations.SerializedName; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
|
||
public class IdentityMapInput { | ||
/** | ||
* @param emails a list of normalized or unnormalized email addresses | ||
* @return a IdentityMapInput instance, to be used in {@link IdentityMapHelper#createEnvelopeForIdentityMapRequest} | ||
*/ | ||
public static IdentityMapInput fromEmails(Iterable<String> emails) { | ||
return new IdentityMapInput(IdentityType.Email, emails, false); | ||
} | ||
|
||
/** | ||
* @param phones a <a href="https://unifiedid.com/docs/getting-started/gs-normalization-encoding#phone-number-normalization">normalized</a> phone number | ||
* @return an IdentityMapInput instance | ||
*/ | ||
public static IdentityMapInput fromPhones(Iterable<String> phones) { | ||
return new IdentityMapInput(IdentityType.Phone, phones, false); | ||
} | ||
|
||
/** | ||
* @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 | ||
* @return an IdentityMapInput instance | ||
*/ | ||
public static IdentityMapInput fromHashedEmails(Iterable<String> hashedEmails) { | ||
return new IdentityMapInput(IdentityType.Email, hashedEmails, true); | ||
} | ||
|
||
/** | ||
* @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 | ||
* @return an IdentityMapInput instance | ||
*/ | ||
public static IdentityMapInput fromHashedPhones(Iterable<String> hashedPhones) { | ||
return new IdentityMapInput(IdentityType.Phone, hashedPhones, true); | ||
} | ||
|
||
private IdentityMapInput(IdentityType identityType, Iterable<String> emailsOrPhones, boolean alreadyHashed) { | ||
if (identityType == IdentityType.Email) { | ||
hashedNormalizedEmails = new ArrayList<>(); | ||
for (String email : emailsOrPhones) { | ||
if (alreadyHashed) { | ||
hashedNormalizedEmails.add(email); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the answer is yet, but does operator return hash exactly as passed without transformations? E.g. lowercase, etc. What happens if the same hash is specified multiple times on input? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the hash is base64 encoded so it's case sensitive and is returned in the same case. |
||
} else { | ||
String hashedEmail = InputUtil.normalizeAndHashEmail(email); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if input contains multiple instances of the same email or variants of it that result in the same hash? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks, good spot. Fixed and added |
||
hashedNormalizedEmails.add(hashedEmail); | ||
addHashedToRawDiiMapping(hashedEmail, email); | ||
} | ||
} | ||
} else { //phone | ||
hashedNormalizedPhones = new ArrayList<>(); | ||
for (String phone : emailsOrPhones) { | ||
if (alreadyHashed) { | ||
hashedNormalizedPhones.add(phone); | ||
} else { | ||
if (!InputUtil.isPhoneNumberNormalized(phone)) { | ||
throw new IllegalArgumentException("phone number is not normalized: " + phone); | ||
} | ||
|
||
String hashedNormalizedPhone = InputUtil.getBase64EncodedHash(phone); | ||
addHashedToRawDiiMapping(hashedNormalizedPhone, phone); | ||
hashedNormalizedPhones.add(hashedNormalizedPhone); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void addHashedToRawDiiMapping(String hashedDii, String rawDii) { | ||
hashedDiiToRawDiis.computeIfAbsent(hashedDii, k -> new ArrayList<>()).add(rawDii); | ||
} | ||
|
||
|
||
List<String> getRawDiis(String identifier) { | ||
final boolean wasInputAlreadyHashed = hashedDiiToRawDiis.isEmpty(); | ||
if (wasInputAlreadyHashed) | ||
return Collections.singletonList(identifier); | ||
return hashedDiiToRawDiis.get(identifier); | ||
} | ||
|
||
@SerializedName("email_hash") | ||
private List<String> hashedNormalizedEmails; | ||
@SerializedName("phone_hash") | ||
private List<String> hashedNormalizedPhones; | ||
|
||
private final transient HashMap<String, List<String>> hashedDiiToRawDiis = new HashMap<>(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if
emailsOrPhones
is empty?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The request still works but getMappedIdentities() and getUnmappedIdentities return empty maps. Added test
identityMapEmptyInput