Skip to content

Commit abebdd8

Browse files
authored
Add auth hash to external Id (#797)
* Add auth to setExternalId * Add tests for new functionality * Add failure block to external id methods * Add tests for external id auth validation
1 parent 0ae1651 commit abebdd8

File tree

11 files changed

+185
-29
lines changed

11 files changed

+185
-29
lines changed

iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,16 @@ - (void)handleMessageAction:(NSString *)actionId {
177177

178178
- (IBAction)setExternalUserId:(UIButton *)sender {
179179
NSString* externalUserId = self.externalUserIdTextField.text;
180-
[OneSignal setExternalUserId:externalUserId withCompletion:^(NSDictionary *results) {
180+
[OneSignal setExternalUserId:externalUserId withSuccess:^(NSDictionary *results) {
181181
NSLog(@"External user id update complete with results: %@", results.description);
182+
} withFailure:^(NSError *error) {
182183
}];
183184
}
184185

185186
- (IBAction)removeExternalUserId:(UIButton *)sender {
186187
[OneSignal removeExternalUserId:^(NSDictionary *results) {
187188
NSLog(@"External user id update complete with results: %@", results.description);
189+
} withFailure:^(NSError *error) {
188190
}];
189191
}
190192

iOS_SDK/OneSignalSDK/Source/OneSignal.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,14 @@ typedef void (^OSEmailSuccessBlock)();
585585

586586
// External user id
587587
// Typedefs defining completion blocks for updating the external user id
588-
typedef void (^OSUpdateExternalUserIdBlock)(NSDictionary* results);
588+
typedef void (^OSUpdateExternalUserIdFailureBlock)(NSError *error);
589+
typedef void (^OSUpdateExternalUserIdSuccessBlock)(NSDictionary *results);
589590

590591
+ (void)setExternalUserId:(NSString * _Nonnull)externalId;
591-
+ (void)setExternalUserId:(NSString * _Nonnull)externalId withCompletion:(OSUpdateExternalUserIdBlock _Nullable)completionBlock;
592+
+ (void)setExternalUserId:(NSString * _Nonnull)externalId withSuccess:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock;
593+
+ (void)setExternalUserId:(NSString *)externalId withExternalIdAuthHashToken:(NSString *)hashToken withSuccess:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock;
592594
+ (void)removeExternalUserId;
593-
+ (void)removeExternalUserId:(OSUpdateExternalUserIdBlock _Nullable)completionBlock;
595+
+ (void)removeExternalUserId:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock;
594596

595597
// In-App Messaging triggers
596598
+ (void)addTrigger:(NSString * _Nonnull)key withValue:(id _Nonnull)value;

iOS_SDK/OneSignalSDK/Source/OneSignal.m

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,12 @@ @implementation OneSignal
206206
BOOL requestedProvisionalAuthorization = false;
207207
BOOL usesAutoPrompt = false;
208208

209+
static BOOL requiresUserIdAuth = false;
209210
static BOOL providesAppNotificationSettings = false;
210211

211212
static BOOL performedOnSessionRequest = false;
212213
static NSString *pendingExternalUserId;
214+
static NSString *pendingExternalUserIdHashToken;
213215

214216
static OSNotificationDisplayType _inFocusDisplayType = OSNotificationDisplayTypeInAppAlert;
215217
+ (void)setInFocusDisplayType:(OSNotificationDisplayType)value {
@@ -493,6 +495,7 @@ + (void)clearStatics {
493495
sessionLaunchTime = [NSDate date];
494496
performedOnSessionRequest = false;
495497
pendingExternalUserId = nil;
498+
pendingExternalUserIdHashToken = nil;
496499

497500
_trackerFactory = nil;
498501
_sessionManager = nil;
@@ -844,6 +847,9 @@ + (void)downloadIOSParamsWithAppId:(NSString *)appId {
844847
delayedEmailParameters = nil;
845848
}
846849
}
850+
if (result[IOS_REQUIRES_USER_ID_AUTHENTICATION]) {
851+
requiresUserIdAuth = [result[IOS_REQUIRES_USER_ID_AUTHENTICATION] boolValue];
852+
}
847853

848854
if (!usesAutoPrompt && result[IOS_USES_PROVISIONAL_AUTHORIZATION] != (id)[NSNull null]) {
849855
[OneSignalUserDefaults.initStandard saveBoolForKey:OSUD_USES_PROVISIONAL_PUSH_AUTHORIZATION withValue:[result[IOS_USES_PROVISIONAL_AUTHORIZATION] boolValue]];
@@ -1676,7 +1682,11 @@ + (void)registerUserInternal {
16761682
if (pendingExternalUserId && ![self.existingPushExternalUserId isEqualToString:pendingExternalUserId])
16771683
dataDic[@"external_user_id"] = pendingExternalUserId;
16781684

1685+
if (pendingExternalUserIdHashToken)
1686+
dataDic[@"external_user_id_auth_hash"] = pendingExternalUserIdHashToken;
1687+
16791688
pendingExternalUserId = nil;
1689+
pendingExternalUserIdHashToken = nil;
16801690

16811691
let deviceModel = [OneSignalHelper getDeviceVariant];
16821692
if (deviceModel)
@@ -2609,41 +2619,56 @@ + (void)setExternalUserId:(NSString * _Nonnull)externalId {
26092619
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setExternalUserId:"])
26102620
return;
26112621

2612-
[self setExternalUserId:externalId withCompletion:nil];
2622+
[self setExternalUserId:externalId withSuccess:nil withFailure:nil];
2623+
}
2624+
2625+
+ (void)setExternalUserId:(NSString * _Nonnull)externalId withSuccess:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock {
2626+
// return if the user has not granted privacy permissions
2627+
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setExternalUserId:withSuccess:withFailure:"])
2628+
return;
2629+
2630+
[self setExternalUserId:externalId withExternalIdAuthHashToken:nil withSuccess:successBlock withFailure:failureBlock];
26132631
}
26142632

2615-
+ (void)setExternalUserId:(NSString * _Nonnull)externalId withCompletion:(OSUpdateExternalUserIdBlock _Nullable)completionBlock {
2633+
+ (void)setExternalUserId:(NSString *)externalId withExternalIdAuthHashToken:(NSString *)hashToken withSuccess:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock {
26162634

26172635
// return if the user has not granted privacy permissions
2618-
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setExternalUserId:withCompletion:"])
2636+
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"setExternalUserId:withExternalIdAuthHashToken:withSuccess:withFailure:"])
26192637
return;
26202638

26212639
// Can't set the external id if init is not done or the app id or user id has not ben set yet
26222640
if (!performedOnSessionRequest) {
26232641
// will be sent as part of the registration/on_session request
26242642
pendingExternalUserId = externalId;
2643+
pendingExternalUserIdHashToken = hashToken;
26252644
return;
26262645
} else if (!self.currentSubscriptionState.userId || !self.app_id) {
26272646
[OneSignal onesignal_Log:ONE_S_LL_WARN message:[NSString stringWithFormat:@"Attempted to set external user id, but %@ is not set", self.app_id == nil ? @"app_id" : @"user_id"]];
2647+
if (failureBlock)
2648+
failureBlock([NSError errorWithDomain:@"com.onesignal" code:0 userInfo:@{@"error" : [NSString stringWithFormat:@"%@ is not set", self.app_id == nil ? @"app_id" : @"user_id"]}]);
2649+
return;
2650+
} else if (requiresUserIdAuth && (!hashToken || hashToken.length == 0)) {
2651+
[OneSignal onesignal_Log:ONE_S_LL_ERROR message:@"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."];
2652+
if (failureBlock)
2653+
failureBlock([NSError errorWithDomain:@"com.onesignal.externalUserId" code:0 userInfo:@{@"error" : @"External User 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."}]);
26282654
return;
26292655
}
26302656

26312657
// Begin constructing the request for the external id update
26322658
let requests = [NSMutableDictionary new];
2633-
requests[@"push"] = [OSRequestUpdateExternalUserId withUserId:externalId withOneSignalUserId:self.currentSubscriptionState.userId appId:self.app_id];
2659+
requests[@"push"] = [OSRequestUpdateExternalUserId withUserId:externalId withUserIdHashToken:hashToken withOneSignalUserId:self.currentSubscriptionState.userId appId:self.app_id];
26342660

26352661
// Check if the email has been set, this will decide on updtaing the external id for the email channel
26362662
if ([self isEmailSetup])
2637-
requests[@"email"] = [OSRequestUpdateExternalUserId withUserId:externalId withOneSignalUserId:self.currentEmailSubscriptionState.emailUserId appId:self.app_id];
2663+
requests[@"email"] = [OSRequestUpdateExternalUserId withUserId:externalId withUserIdHashToken:hashToken withOneSignalUserId:self.currentEmailSubscriptionState.emailUserId appId:self.app_id];
26382664

26392665
// Make sure this is not a duplicate request, if the email and push channels are aligned correctly with the same external id
26402666
if (![self shouldUpdateExternalUserId:externalId withRequests:requests]) {
26412667
// Use callback to return success for both cases here, since push and
26422668
// email (if email is not setup, email is not included) have been set already
26432669
let results = [self getDuplicateExternalUserIdResponse:externalId withRequests:requests];
2644-
if (completionBlock)
2645-
completionBlock(results);
2646-
2670+
if (successBlock)
2671+
successBlock(results);
26472672
return;
26482673
}
26492674

@@ -2654,8 +2679,8 @@ + (void)setExternalUserId:(NSString * _Nonnull)externalId withCompletion:(OSUpda
26542679
if (results[@"email"] && results[@"email"][@"success"] && [results[@"email"][@"success"] boolValue])
26552680
[OneSignalUserDefaults.initStandard saveStringForKey:OSUD_EMAIL_EXTERNAL_USER_ID withValue:externalId];
26562681

2657-
if (completionBlock)
2658-
completionBlock(results);
2682+
if (successBlock)
2683+
successBlock(results);
26592684
}];
26602685
}
26612686

@@ -2664,15 +2689,15 @@ + (void)removeExternalUserId {
26642689
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"removeExternalUserId"])
26652690
return;
26662691

2667-
[self setExternalUserId:@"" withCompletion:nil];
2692+
[self setExternalUserId:@""];
26682693
}
26692694

2670-
+ (void)removeExternalUserId:(OSUpdateExternalUserIdBlock _Nullable)completionBlock {
2695+
+ (void)removeExternalUserId:(OSUpdateExternalUserIdSuccessBlock _Nullable)successBlock withFailure:(OSUpdateExternalUserIdFailureBlock _Nullable)failureBlock {
26712696
// return if the user has not granted privacy permissions
26722697
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"removeExternalUserId:"])
26732698
return;
26742699

2675-
[self setExternalUserId:@"" withCompletion:completionBlock];
2700+
[self setExternalUserId:@"" withSuccess:successBlock withFailure:failureBlock];
26762701
}
26772702

26782703
+ (NSString*)existingPushExternalUserId {

iOS_SDK/OneSignalSDK/Source/OneSignalCommonDefines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
// iOS Parameter Names
122122
#define IOS_USES_PROVISIONAL_AUTHORIZATION @"uses_provisional_auth"
123123
#define IOS_REQUIRES_EMAIL_AUTHENTICATION @"require_email_auth"
124+
#define IOS_REQUIRES_USER_ID_AUTHENTICATION @"require_user_id_auth"
124125
#define IOS_RECEIVE_RECEIPTS_ENABLE @"receive_receipts_enable"
125126
#define IOS_OUTCOMES_V2_SERVICE_ENABLE @"v2_enabled"
126127

iOS_SDK/OneSignalSDK/Source/Requests.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ NS_ASSUME_NONNULL_END
137137
@end
138138

139139
@interface OSRequestUpdateExternalUserId : OneSignalRequest
140-
+ (instancetype _Nonnull)withUserId:(NSString * _Nullable)externalId withOneSignalUserId:(NSString * _Nonnull)userId appId:(NSString * _Nonnull)appId;
140+
+ (instancetype _Nonnull)withUserId:(NSString * _Nullable)externalId withUserIdHashToken:(NSString * _Nullable)hashToken withOneSignalUserId:(NSString *)userId appId:(NSString *)appId;
141141
@end
142142

143143
@interface OSRequestSendOutcomesV1ToServer : OneSignalRequest

iOS_SDK/OneSignalSDK/Source/Requests.m

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,12 +447,17 @@ + (instancetype)withAppId:(NSString *)appId previewUUID:(NSString *)previewUUID
447447
@end
448448

449449
@implementation OSRequestUpdateExternalUserId
450-
+ (instancetype _Nonnull)withUserId:(NSString * _Nullable)externalId withOneSignalUserId:(NSString *)userId appId:(NSString *)appId {
450+
+ (instancetype _Nonnull)withUserId:(NSString * _Nullable)externalId withUserIdHashToken:(NSString * _Nullable)hashToken withOneSignalUserId:(NSString *)userId appId:(NSString *)appId {
451451
NSString *msg = [NSString stringWithFormat:@"App ID: %@, external ID: %@", appId, externalId];
452452
[OneSignal onesignal_Log:ONE_S_LL_DEBUG message:msg];
453453

454454
let request = [OSRequestUpdateExternalUserId new];
455-
request.parameters = @{@"app_id" : appId, @"external_user_id" : externalId ?: @""};
455+
NSMutableDictionary *parametres = [NSMutableDictionary new];
456+
[parametres setObject:appId forKey:@"app_id"];
457+
[parametres setObject:externalId ?: @"" forKey:@"external_user_id"];
458+
if (hashToken && [hashToken length] > 0)
459+
[parametres setObject:hashToken forKey:@"external_user_id_auth_hash"];
460+
request.parameters = parametres;
456461
request.method = PUT;
457462
request.path = [NSString stringWithFormat:@"players/%@", userId];
458463

iOS_SDK/OneSignalSDK/UnitTests/RequestTests.m

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ @implementation RequestTests {
4545
NSString *testAppId;
4646
NSString *testUserId;
4747
NSString *testExternalUserId;
48+
NSString *testExternalUserIdHashToken;
4849
NSString *testEmailUserId;
4950
NSString *testMessageId;
5051
NSString *testEmailAddress;
@@ -67,6 +68,7 @@ - (void)setUp {
6768
testUserId = @"test_user_id";
6869
testEmailUserId = @"test_email_user_id";
6970
testExternalUserId = @"test_external_id";
71+
testExternalUserIdHashToken = @"testExternalUserIdHashToken";
7072
testEmailAddress = @"[email protected]";
7173
testMessageId = @"test_message_id";
7274
testInAppMessageId = @"test_in_app_message_id";
@@ -672,7 +674,7 @@ - (void)testLoadMessageContent {
672674
}
673675

674676
- (void)testSendExternalUserId {
675-
let request = [OSRequestUpdateExternalUserId withUserId:testExternalUserId withOneSignalUserId:testUserId appId:testAppId];
677+
let request = [OSRequestUpdateExternalUserId withUserId:testExternalUserId withUserIdHashToken:nil withOneSignalUserId:testUserId appId:testAppId];
676678

677679
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
678680

@@ -681,4 +683,14 @@ - (void)testSendExternalUserId {
681683
XCTAssertTrue(checkHttpBody(request.urlRequest.HTTPBody, @{@"app_id" : testAppId, @"external_user_id" : testExternalUserId}));
682684
}
683685

686+
- (void)testSendExternalWithAuthUserId {
687+
let request = [OSRequestUpdateExternalUserId withUserId:testExternalUserId withUserIdHashToken:testExternalUserIdHashToken withOneSignalUserId:testUserId appId:testAppId];
688+
689+
let correctUrl = correctUrlWithPath([NSString stringWithFormat:@"players/%@", testUserId]);
690+
691+
XCTAssertTrue([correctUrl isEqualToString:request.urlRequest.URL.absoluteString]);
692+
693+
XCTAssertTrue(checkHttpBody(request.urlRequest.HTTPBody, @{@"app_id" : testAppId, @"external_user_id" : testExternalUserId, @"external_user_id_auth_hash" : testExternalUserIdHashToken}));
694+
}
695+
684696
@end

iOS_SDK/OneSignalSDK/UnitTests/Shadows/OneSignalClientOverrider.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
+(void)runBackgroundThreads;
4444
+(NSString *)lastHTTPRequestType;
4545
+(void)setRequiresEmailAuth:(BOOL)required;
46+
+(void)setRequiresExternalIdAuth:(BOOL)required;
4647
+(BOOL)hasExecutedRequestOfType:(Class)type;
4748
+(void)setShouldUseProvisionalAuth:(BOOL)provisional;
4849
+(void)disableExecuteRequestOverride:(BOOL)disable;

iOS_SDK/OneSignalSDK/UnitTests/Shadows/OneSignalClientOverrider.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ @implementation OneSignalClientOverrider
5050
static dispatch_queue_t executionQueue;
5151
static NSString *lastHTTPRequestType;
5252
static BOOL requiresEmailAuth = false;
53+
static BOOL requiresExternalIdAuth = false;
5354
static BOOL shouldUseProvisionalAuthorization = false; //new in iOS 12 (aka Direct to History)
5455
static BOOL disableOverride = false;
5556
static NSMutableArray<OneSignalRequest *> *executedRequests;
@@ -76,6 +77,7 @@ + (NSDictionary*)iosParamsResponse {
7677
return @{
7778
@"fba": @true,
7879
IOS_REQUIRES_EMAIL_AUTHENTICATION : @(requiresEmailAuth),
80+
IOS_REQUIRES_USER_ID_AUTHENTICATION : @(requiresExternalIdAuth),
7981
IOS_USES_PROVISIONAL_AUTHORIZATION : @(shouldUseProvisionalAuthorization),
8082
OUTCOMES_PARAM : iOSParamsOutcomes
8183
};
@@ -258,6 +260,8 @@ + (void)reset:(XCTestCase*)testInstance {
258260
[executedRequests removeAllObjects];
259261
mockResponses = [NSMutableDictionary new];
260262
iOSParamsOutcomes = @{};
263+
requiresEmailAuth = false;
264+
requiresExternalIdAuth = false;
261265
}
262266

263267
+ (void)setLastHTTPRequest:(NSDictionary*)value {
@@ -287,6 +291,10 @@ + (void)setRequiresEmailAuth:(BOOL)required {
287291
requiresEmailAuth = required;
288292
}
289293

294+
+ (void)setRequiresExternalIdAuth:(BOOL)required {
295+
requiresExternalIdAuth = required;
296+
}
297+
290298
+ (void)setShouldUseProvisionalAuth:(BOOL)provisional {
291299
shouldUseProvisionalAuthorization = provisional;
292300
}

iOS_SDK/OneSignalSDK/UnitTests/UnitTestCommonMethods.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#import "UIApplication+OneSignal.h"
3232
#import "OneSignalNotificationCategoryController.h"
3333

34+
#define TEST_EXTERNAL_USER_ID_HASH_TOKEN @"i_am_a_test_external_user_id_hash_token"
3435
#define TEST_EXTERNAL_USER_ID @"i_am_a_test_external_user_id"
3536
#define TEST_EMAIL @"[email protected]"
3637

0 commit comments

Comments
 (0)