Skip to content

Commit 73a6f72

Browse files
committed
Added more test APIs
1 parent f8ed543 commit 73a6f72

File tree

2 files changed

+131
-1
lines changed

2 files changed

+131
-1
lines changed

src/main/java/com/uid2/admin/vertx/service/SaltService.java

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ public void setupRoutes(Router router) {
128128
}
129129
}, new AuditParams(List.of(), Collections.emptyList()), Role.MAINTAINER, Role.SECRET_ROTATION));
130130

131+
router.post("/api/salt/generate").blockingHandler(auth.handle(ctx -> {
132+
synchronized (writeLock) {
133+
this.handleSaltGenerate(ctx);
134+
}
135+
}, new AuditParams(List.of(), Collections.emptyList()), Role.MAINTAINER, Role.SECRET_ROTATION));
136+
137+
router.post("/api/salt/optout").blockingHandler(auth.handle(ctx -> {
138+
synchronized (writeLock) {
139+
this.handleSaltOptout(ctx);
140+
}
141+
}, new AuditParams(List.of(), Collections.emptyList()), Role.MAINTAINER, Role.SECRET_ROTATION));
142+
131143
router.post("/api/salt/simulateToken").blockingHandler(auth.handle(ctx -> {
132144
synchronized (writeLock) {
133145
this.handleSaltSimulateToken(ctx);
@@ -401,6 +413,67 @@ private void handleSaltCompare(RoutingContext rc) {
401413
}
402414
}
403415

416+
private void handleSaltGenerate(RoutingContext rc) {
417+
try {
418+
RotatingSaltProvider.SaltSnapshot snapshot = saltProvider.getSnapshots().getLast();
419+
420+
String v2Email = null;
421+
String v4Email = null;
422+
while (v2Email == null || v4Email == null) {
423+
String email = randomEmail();
424+
SaltEntry salt = getSalt(email, snapshot);
425+
if (salt.currentSalt() != null) {
426+
v2Email = email;
427+
} else {
428+
v4Email = email;
429+
}
430+
}
431+
432+
JsonNode v2GenerateResponse = v2TokenGenerate(v2Email);
433+
JsonNode v4GenerateResponse = v2TokenGenerate(v4Email);
434+
435+
JsonNode v2MapResponse = v3IdentityMap(List.of(v2Email));
436+
JsonNode v4MapResponse = v3IdentityMap(List.of(v4Email));
437+
438+
String v2UidToken = v2GenerateResponse.at("/body/advertising_token").asText();
439+
String v4UidToken = v4GenerateResponse.at("/body/advertising_token").asText();
440+
441+
String v2RawUid = v2MapResponse.at("/body/email").get(0).at("/u").asText();
442+
String v4RawUid = v4MapResponse.at("/body/email").get(0).at("/u").asText();
443+
444+
rc.response()
445+
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
446+
.end();
447+
} catch (Exception e) {
448+
LOGGER.error(e.getMessage(), e);
449+
rc.fail(500, e);
450+
}
451+
}
452+
453+
private void handleSaltOptout(RoutingContext rc) {
454+
try {
455+
final String candidateOperatorUrl = RequestUtil.getString(rc, "candidate_operator_url").orElse("");
456+
final String candidateApiKey = RequestUtil.getString(rc, "candidate_api_key").orElse("");
457+
final String candidateApiSecret = RequestUtil.getString(rc, "candidate_api_secret").orElse("");
458+
final String[] optoutEmails = RequestUtil.getString(rc, "emails").orElse("").split(",");
459+
final String[] optoutPhones = RequestUtil.getString(rc, "phones").orElse("").split(",");
460+
461+
for (String email : optoutEmails) {
462+
v2TokenLogout("email", email, candidateOperatorUrl, candidateApiKey, candidateApiSecret);
463+
}
464+
for (String phone : optoutPhones) {
465+
v2TokenLogout("phone", phone, candidateOperatorUrl, candidateApiKey, candidateApiSecret);
466+
}
467+
468+
rc.response()
469+
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
470+
.end();
471+
} catch (Exception e) {
472+
LOGGER.error(e.getMessage(), e);
473+
rc.fail(500, e);
474+
}
475+
}
476+
404477
private void handleSaltSimulateToken(RoutingContext rc) {
405478
try {
406479
final double fraction = RequestUtil.getDouble(rc, "fraction").orElse(0.002740);
@@ -932,9 +1005,10 @@ private JsonNode v3IdentityMap(List<String> emails, String baseUrl, String key,
9321005
}
9331006
}
9341007
reqBody.append("] }");
935-
9361008
V2Envelope envelope = v2CreateEnvelope(reqBody.toString(), secret);
1009+
9371010
Map<String, String> headers = Map.of("Authorization", String.format("Bearer %s", key));
1011+
9381012
HttpResponse<String> response = HTTP_CLIENT.post(String.format("%s/v3/identity/map", baseUrl), envelope.envelope(), headers);
9391013
return v2DecryptEncryptedResponse(response.body(), envelope.nonce(), secret);
9401014
}
@@ -956,6 +1030,16 @@ private JsonNode v2TokenRefresh(String refreshToken, String refreshResponseKey)
9561030
return v2DecryptRefreshResponse(response.body(), refreshResponseKey);
9571031
}
9581032

1033+
private JsonNode v2TokenLogout(String type, String identity, String baseUrl, String key, String secret) throws Exception {
1034+
String reqBody = String.format("{\"%s\":\"%s\"}".formatted(type, identity));
1035+
V2Envelope envelope = v2CreateEnvelope(reqBody, secret);
1036+
1037+
Map<String, String> headers = Map.of("Authorization", String.format("Bearer %s", key));
1038+
1039+
HttpResponse<String> response = HTTP_CLIENT.post(String.format("%s/v2/token/logout", baseUrl), envelope.envelope(), headers);
1040+
return v2DecryptEncryptedResponse(response.body(), envelope.nonce(), secret);
1041+
}
1042+
9591043
private String randomEmail() {
9601044
return "email_" + Math.abs(SECURE_RANDOM.nextLong()) + "@example.com";
9611045
}

webroot/adm/salt.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ <h1>UID2 Env - Salt Management</h1>
101101
defaultValue: true
102102
}
103103

104+
const optoutEmailsInput = {
105+
name: 'optoutEmails',
106+
label: 'Optout Emails'
107+
}
108+
109+
const optoutPhonesInput = {
110+
name: 'optoutPhones',
111+
label: 'Optout Phones'
112+
}
113+
104114
const preMigrationIterationsInput = {
105115
name: 'preMigrationIterations',
106116
label: 'Step 1 - Pre-Migration Iterations',
@@ -214,6 +224,42 @@ <h1>UID2 Env - Salt Management</h1>
214224
}
215225
},
216226
},
227+
{
228+
id: 'generate',
229+
title: 'Generate',
230+
role: 'maintainer',
231+
inputs: [
232+
],
233+
apiCall: {
234+
method: 'POST',
235+
getUrl: (inputs) => {
236+
return `/api/salt/generate`;
237+
}
238+
},
239+
},
240+
{
241+
id: 'optout',
242+
title: 'Optout',
243+
role: 'maintainer',
244+
inputs: [
245+
candidateOperatorUrlInput,
246+
candidateApiKeyInput,
247+
candidateApiSecretInput,
248+
optoutEmailsInput,
249+
optoutPhonesInput
250+
],
251+
apiCall: {
252+
method: 'POST',
253+
getUrl: (inputs) => {
254+
const candidateOperatorUrl = encodeURIComponent(inputs.candidateOperatorUrl);
255+
const candidateApiKey = encodeURIComponent(inputs.candidateApiKey);
256+
const candidateApiSecret = encodeURIComponent(inputs.candidateApiSecret);
257+
const emails = encodeURIComponent(inputs.optoutEmails);
258+
const phones = encodeURIComponent(inputs.optoutPhones);
259+
return `/api/salt/optout?candidate_operator_url=${candidateOperatorUrl}&candidate_api_key=${candidateApiKey}&candidate_api_secret=${candidateApiSecret}&emails=${emails}&phones=${phones}`;
260+
}
261+
},
262+
},
217263
{
218264
id: 'simulateToken',
219265
title: 'Simulate Token',

0 commit comments

Comments
 (0)