Skip to content

Commit f9eb83c

Browse files
authored
Add auth hash to external Id (#1210)
* Add auth to setExternalId * Add tests for new functionality
1 parent 3491e22 commit f9eb83c

File tree

5 files changed

+116
-7
lines changed

5 files changed

+116
-7
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignal.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,31 @@ public static class SendTagsError {
200200
public String getMessage() { return message; }
201201
}
202202

203+
public enum ExternalIdErrorType {
204+
REQUIRES_EXTERNAL_ID_AUTH, INVALID_OPERATION, NETWORK
205+
}
206+
207+
public static class ExternalIdError {
208+
private ExternalIdErrorType type;
209+
private String message;
210+
211+
ExternalIdError(ExternalIdErrorType type, String message) {
212+
this.type = type;
213+
this.message = message;
214+
}
215+
216+
public ExternalIdErrorType getType() {
217+
return type;
218+
}
219+
220+
public String getMessage() {
221+
return message;
222+
}
223+
}
224+
203225
public interface OSExternalUserIdUpdateCompletionHandler {
204226
void onComplete(JSONObject results);
227+
void onFailure(ExternalIdError error);
205228
}
206229

207230
interface OSInternalExternalUserIdUpdateCompletionHandler {
@@ -1549,11 +1572,18 @@ public void run() {
15491572
}
15501573

15511574
public static void setExternalUserId(@NonNull final String externalId) {
1552-
setExternalUserId(externalId, null);
1575+
setExternalUserId(externalId, null, null);
15531576
}
15541577

15551578
public static void setExternalUserId(@NonNull final String externalId, @Nullable final OSExternalUserIdUpdateCompletionHandler completionCallback) {
1579+
setExternalUserId(externalId, null, completionCallback);
1580+
}
15561581

1582+
public static void setExternalUserId(@NonNull final String externalId, @Nullable final String externalIdAuthHash) {
1583+
setExternalUserId(externalId, externalIdAuthHash, null);
1584+
}
1585+
1586+
public static void setExternalUserId(@NonNull final String externalId, @Nullable final String externalIdAuthHash, @Nullable final OSExternalUserIdUpdateCompletionHandler completionCallback) {
15571587
if (shouldLogUserPrivacyConsentErrorMessageForMethodName("setExternalUserId()"))
15581588
return;
15591589

@@ -1565,8 +1595,20 @@ public void run() {
15651595
return;
15661596
}
15671597

1598+
if (remoteParams != null && remoteParams.useUserIdAuth && externalIdAuthHash == null) {
1599+
String errorMessage = "External Id authentication (auth token) is set to REQUIRED for this application. Please provide an auth token from your backend server or change the setting in the OneSignal dashboard.";
1600+
if (completionCallback != null)
1601+
completionCallback.onFailure(new ExternalIdError(ExternalIdErrorType.REQUIRES_EXTERNAL_ID_AUTH, errorMessage));
1602+
Log(LOG_LEVEL.ERROR, errorMessage);
1603+
return;
1604+
}
1605+
1606+
String lowerCaseIdAuthHash = externalIdAuthHash;
1607+
if (lowerCaseIdAuthHash != null)
1608+
lowerCaseIdAuthHash = externalIdAuthHash.toLowerCase();
1609+
15681610
try {
1569-
OneSignalStateSynchronizer.setExternalUserId(externalId, completionCallback);
1611+
OneSignalStateSynchronizer.setExternalUserId(externalId, lowerCaseIdAuthHash, completionCallback);
15701612
} catch (JSONException exception) {
15711613
String operation = externalId.equals("") ? "remove" : "set";
15721614
onesignalLog(LOG_LEVEL.ERROR, "Attempted to " + operation + " external ID but encountered a JSON exception");

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalRemoteParams.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static class Params {
7676
String googleProjectNumber;
7777
boolean enterprise;
7878
boolean useEmailAuth;
79+
boolean useUserIdAuth;
7980
JSONArray notificationChannels;
8081
boolean firebaseAnalytics;
8182
boolean restoreTTLFilter;
@@ -164,6 +165,7 @@ static private void processJson(String json, final @NonNull CallBack callBack) {
164165
Params params = new Params() {{
165166
enterprise = responseJson.optBoolean("enterp", false);
166167
useEmailAuth = responseJson.optBoolean("use_email_auth", false);
168+
useUserIdAuth = responseJson.optBoolean("require_user_id_auth", false);
167169
notificationChannels = responseJson.optJSONArray("chnl_lst");
168170
firebaseAnalytics = responseJson.optBoolean("fba", false);
169171
restoreTTLFilter = responseJson.optBoolean("restore_ttl_filter", true);

OneSignalSDK/onesignal/src/main/java/com/onesignal/OneSignalStateSynchronizer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static void logoutEmail() {
198198
getEmailStateSynchronizer().logoutEmail();
199199
}
200200

201-
static void setExternalUserId(String externalId, final OneSignal.OSExternalUserIdUpdateCompletionHandler completionHandler) throws JSONException {
201+
static void setExternalUserId(String externalId, String externalIdAuthHash, final OneSignal.OSExternalUserIdUpdateCompletionHandler completionHandler) throws JSONException {
202202
final JSONObject responses = new JSONObject();
203203
// Create a handler for internal usage, this is where the developers completion handler will be called,
204204
// which happens once all handlers for each channel have been processed
@@ -233,11 +233,11 @@ public void run() {
233233
}
234234
};
235235

236-
getPushStateSynchronizer().setExternalUserId(externalId, handler);
236+
getPushStateSynchronizer().setExternalUserId(externalId, externalIdAuthHash, handler);
237237

238238
// Make sure we are only setting external user id for email when an email is actually set
239239
if (OneSignal.hasEmailId())
240-
getEmailStateSynchronizer().setExternalUserId(externalId, handler);
240+
getEmailStateSynchronizer().setExternalUserId(externalId, externalIdAuthHash, handler);
241241
}
242242

243243
// This is to indicate that StateSynchronizer can start making REST API calls

OneSignalSDK/onesignal/src/main/java/com/onesignal/UserStateSynchronizer.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,10 +502,14 @@ void syncHashedEmail(JSONObject emailFields) {
502502
getUserStateForModification().generateJsonDiffFromIntoSyncValued(emailFields, null);
503503
}
504504

505-
void setExternalUserId(final String externalId, OneSignal.OSInternalExternalUserIdUpdateCompletionHandler handler) throws JSONException {
505+
void setExternalUserId(final String externalId, final String externalIdAuthHash, OneSignal.OSInternalExternalUserIdUpdateCompletionHandler handler) throws JSONException {
506506
if (handler != null)
507507
this.externalUserIdUpdateHandlers.add(handler);
508-
getUserStateForModification().putOnSyncValues("external_user_id", externalId);
508+
509+
UserState userState = getUserStateForModification();
510+
userState.putOnSyncValues("external_user_id", externalId);
511+
if (externalIdAuthHash != null)
512+
userState.putOnSyncValues("external_user_id_auth_hash", externalIdAuthHash);
509513
}
510514

511515
abstract void setSubscription(boolean enable);

OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
import java.util.concurrent.atomic.AtomicBoolean;
123123
import java.util.regex.Pattern;
124124

125+
import static com.onesignal.OneSignal.ExternalIdErrorType.REQUIRES_EXTERNAL_ID_AUTH;
125126
import static com.onesignal.OneSignalPackagePrivateHelper.GcmBroadcastReceiver_processBundle;
126127
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationBundleProcessor_Process;
127128
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationOpenedProcessor_processFromContext;
@@ -214,12 +215,18 @@ public void notificationOpened(OSNotificationOpenResult openedResult) {
214215
}
215216

216217
private static JSONObject lastExternalUserIdResponse;
218+
private static OneSignal.ExternalIdError lastExternalUserIdError;
217219
private static OneSignal.OSExternalUserIdUpdateCompletionHandler getExternalUserIdUpdateCompletionHandler() {
218220
return new OneSignal.OSExternalUserIdUpdateCompletionHandler() {
219221
@Override
220222
public void onComplete(JSONObject results) {
221223
lastExternalUserIdResponse = results;
222224
}
225+
226+
@Override
227+
public void onFailure(OneSignal.ExternalIdError error) {
228+
lastExternalUserIdError = error;
229+
}
223230
};
224231
}
225232

@@ -238,6 +245,7 @@ private static void cleanUp() throws Exception {
238245
notificationOpenedMessage = null;
239246
lastGetTags = null;
240247
lastExternalUserIdResponse = null;
248+
lastExternalUserIdError = null;
241249

242250
ShadowGMSLocationController.reset();
243251
TestHelpers.beforeTestInitAndCleanup();
@@ -4124,6 +4132,59 @@ public void shouldSendExternalUserIdBeforeRegistration() throws Exception {
41244132
assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
41254133
}
41264134

4135+
@Test
4136+
public void shouldSetExternalIdWithAuthHash() throws Exception {
4137+
ShadowOneSignalRestClient.paramExtras = new JSONObject().put("require_user_id_auth", true);
4138+
4139+
OneSignalInit();
4140+
threadAndTaskWait();
4141+
4142+
String testExternalId = "test_ext_id";
4143+
4144+
OneSignal.setExternalUserId(testExternalId, getExternalUserIdUpdateCompletionHandler());
4145+
threadAndTaskWait();
4146+
4147+
assertNotNull(lastExternalUserIdError);
4148+
assertEquals(REQUIRES_EXTERNAL_ID_AUTH, lastExternalUserIdError.getType());
4149+
}
4150+
4151+
@Test
4152+
public void shouldSetExternalIdWithAuthHashAfterRegistration() throws Exception {
4153+
OneSignalInit();
4154+
threadAndTaskWait();
4155+
4156+
String testExternalId = "test_ext_id";
4157+
String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
4158+
4159+
OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
4160+
threadAndTaskWait();
4161+
4162+
assertEquals(3, ShadowOneSignalRestClient.networkCallCount);
4163+
4164+
ShadowOneSignalRestClient.Request externalIdRequest = ShadowOneSignalRestClient.requests.get(2);
4165+
assertEquals(ShadowOneSignalRestClient.REST_METHOD.PUT, externalIdRequest.method);
4166+
assertEquals(testExternalId, externalIdRequest.payload.getString("external_user_id"));
4167+
assertEquals(mockExternalIdHash, externalIdRequest.payload.getString("external_user_id_auth_hash"));
4168+
}
4169+
4170+
@Test
4171+
public void shouldSetExternalIdWithAuthHashBeforeRegistration() throws Exception {
4172+
String testExternalId = "test_ext_id";
4173+
String mockExternalIdHash = new String(new char[64]).replace('\0', '0');
4174+
4175+
OneSignal.setExternalUserId(testExternalId, mockExternalIdHash, null);
4176+
4177+
OneSignalInit();
4178+
threadAndTaskWait();
4179+
4180+
assertEquals(2, ShadowOneSignalRestClient.networkCallCount);
4181+
4182+
ShadowOneSignalRestClient.Request registrationRequest = ShadowOneSignalRestClient.requests.get(1);
4183+
assertEquals(ShadowOneSignalRestClient.REST_METHOD.POST, registrationRequest.method);
4184+
assertEquals(testExternalId, registrationRequest.payload.getString("external_user_id"));
4185+
assertEquals(mockExternalIdHash, registrationRequest.payload.getString("external_user_id_auth_hash"));
4186+
}
4187+
41274188
@Test
41284189
public void shouldRemoveExternalUserId() throws Exception {
41294190
OneSignal.setExternalUserId("test_ext_id");

0 commit comments

Comments
 (0)