Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e7eeba5
create simple way to fire invalid Jwt callback
emawby Sep 3, 2024
c0ad6c3
Adding OSJwtInvalidatedEvent and updating the JWT callback
emawby Sep 3, 2024
f926109
refactor in UserExecutor to handle 401s
emawby Sep 4, 2024
02acc2a
Unit tests for UserExecutor with identity verification on
emawby Sep 4, 2024
2530e2f
Fire callback for 401 error in property executor
emawby Sep 4, 2024
c0156d7
fire Jwt callback from subscription executor
emawby Sep 4, 2024
d5514e4
fire Jwt callback for add and remove aliases 401
emawby Sep 4, 2024
5afab13
Remove message for invalid handler
emawby Sep 11, 2024
1d0b97f
Fire JWT callback from IAMs
emawby Sep 11, 2024
f3cb3d8
Store UserExecutor requests that need auth
emawby Sep 11, 2024
aca978e
store property update requests that need auth
emawby Sep 11, 2024
1ae0deb
store alias update requests that need auth
emawby Sep 11, 2024
3542d34
Adding work in progress Subscription executor auth pends
emawby Sep 11, 2024
d90f0d2
[nit] run swiftlint
nan-li Sep 23, 2024
01c2069
cache the pending auth requests in executors
nan-li Sep 24, 2024
d579f06
Add pending to fetch user requests
nan-li Sep 24, 2024
19df3db
Don't fire JWT invalid listeners multiple times
nan-li Sep 24, 2024
cccb58c
Subscription executor wrap up, add some more tests
nan-li Sep 24, 2024
c27842c
[nits] Move public protocols out of User Manager file
nan-li Sep 24, 2024
74e4ef7
Update tests
nan-li Sep 25, 2024
0156328
Update the remote params JWT key
nan-li Oct 1, 2024
a2420ee
Re-use existing identity models for new users
nan-li Oct 1, 2024
5433ebb
Remove duplicate Create User requests
nan-li Oct 1, 2024
01fde6f
Don't send push sub for previous users to avoid transfer
nan-li Oct 1, 2024
8d0d088
Extract out User Manager Loggable extension for file length
nan-li Oct 2, 2024
b5ae642
Update JWT invalidated listener and event API
nan-li Oct 3, 2024
7d5db5e
Update tests after JWT listener API change
nan-li Oct 3, 2024
0dc2cee
Disable push sub when logout called (JWT on)
nan-li Oct 2, 2024
5ad412f
Fire user observer on logout (JWT on)
nan-li Oct 2, 2024
0d9c62d
[nit] move a method to extension for swiftlint
nan-li Oct 3, 2024
1f60b08
[nit] Clean up logging, remove hardcoded prints
nan-li Oct 4, 2024
0a81b7a
Revert back to production servers
nan-li Oct 4, 2024
1e7bce1
Merge pull request #1488 from OneSignal/identity_verification_logout
nan-li Oct 4, 2024
d4588f5
Merge pull request #1487 from OneSignal/identity_verification_multipl…
nan-li Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ @implementation AppDelegate

OneSignalNotificationCenterDelegate *_notificationDelegate;

// ECM Should we ship these typedefs in OneSignalFramework.h to make them available to Objective C customers?
typedef void (^JwtCompletionBlock)(NSString*);
typedef void (^JwtExpiredBlock)(NSString *, JwtCompletionBlock);

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// [FIRApp configure];
Expand Down Expand Up @@ -73,6 +77,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[OneSignal.Notifications addPermissionObserver:self];
[OneSignal.InAppMessages addClickListener:self];


[OneSignal.User onJwtInvalidatedWithInvalidatedHandler:^(OSJwtInvalidatedEvent * _Nonnull invalidatedEvent) {
NSLog(@"JWT INVALIDATED CALLBACK FOR: %@", invalidatedEvent.externalId);
}];

NSLog(@"UNUserNotificationCenter.delegate: %@", UNUserNotificationCenter.currentNotificationCenter.delegate);

#if TARGET_OS_MACCATALYST
Expand All @@ -86,8 +95,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
return YES;
}

#define ONESIGNAL_APP_ID_DEFAULT @"STAGING_APP_HERE"
#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"YOUR_APP_ID_HERE"
#define ONESIGNAL_APP_ID_DEFAULT @"0139bd6f-451f-438c-8886-4e0f0fe3a085"
#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"0139bd6f-451f-438c-8886-4e0f0fe3a085"

+ (NSString*)getOneSignalAppId {
NSString* userDefinedAppId = [[NSUserDefaults standardUserDefaults] objectForKey:ONESIGNAL_APP_ID_KEY_FOR_TESTING];
Expand Down
20 changes: 20 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,16 @@
DE16C14524D3724700670EFA /* OneSignalLifecycleObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = DE16C14324D3724700670EFA /* OneSignalLifecycleObserver.m */; };
DE16C14724D3727200670EFA /* OneSignalLifecycleObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = DE16C14624D3727200670EFA /* OneSignalLifecycleObserver.h */; };
DE16C17024D3989A00670EFA /* OneSignalLifecycleObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = DE16C14324D3724700670EFA /* OneSignalLifecycleObserver.m */; };
DE1DD0602C87D87B00787071 /* OSJwtInvalidatedEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE1DD05F2C87D87B00787071 /* OSJwtInvalidatedEvent.swift */; };
DE20425E24E21C2C00350E4F /* UIApplication+OneSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = DE20425D24E21C2C00350E4F /* UIApplication+OneSignal.m */; };
DE20425F24E21C2C00350E4F /* UIApplication+OneSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = DE20425D24E21C2C00350E4F /* UIApplication+OneSignal.m */; };
DE20426024E21C2C00350E4F /* UIApplication+OneSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = DE20425D24E21C2C00350E4F /* UIApplication+OneSignal.m */; };
DE2D8F452947D85800844084 /* OneSignalExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE7D17F927026BA3002D3A5D /* OneSignalExtension.framework */; };
DE2D8F4A2947D86200844084 /* OneSignalOutcomes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE7D188027037F43002D3A5D /* OneSignalOutcomes.framework */; };
DE3568EA2C88F56600AF447C /* PropertyExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3568E92C88F56600AF447C /* PropertyExecutorTests.swift */; };
DE3568EC2C88F5BD00AF447C /* OneSignalExecutorMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3568EB2C88F5BD00AF447C /* OneSignalExecutorMocks.swift */; };
DE3568F02C89067400AF447C /* SubscriptionsExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3568EF2C89067400AF447C /* SubscriptionsExecutorTests.swift */; };
DE3568F22C8911EA00AF447C /* IdentityExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3568F12C8911EA00AF447C /* IdentityExecutorTests.swift */; };
DE3784842888CFF900453A8E /* OneSignalUser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE69E19B282ED8060090BB3D /* OneSignalUser.framework */; };
DE3784852888D00300453A8E /* OneSignalUser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE69E19B282ED8060090BB3D /* OneSignalUser.framework */; };
DE3784862888D00B00453A8E /* OneSignalUser.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DE69E19B282ED8060090BB3D /* OneSignalUser.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -1510,8 +1515,13 @@
CACBAAAB218A662B000ACAA5 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
DE16C14324D3724700670EFA /* OneSignalLifecycleObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalLifecycleObserver.m; sourceTree = "<group>"; };
DE16C14624D3727200670EFA /* OneSignalLifecycleObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalLifecycleObserver.h; sourceTree = "<group>"; };
DE1DD05F2C87D87B00787071 /* OSJwtInvalidatedEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSJwtInvalidatedEvent.swift; sourceTree = "<group>"; };
DE20425C24E21C1500350E4F /* UIApplication+OneSignal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIApplication+OneSignal.h"; sourceTree = "<group>"; };
DE20425D24E21C2C00350E4F /* UIApplication+OneSignal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIApplication+OneSignal.m"; sourceTree = "<group>"; };
DE3568E92C88F56600AF447C /* PropertyExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyExecutorTests.swift; sourceTree = "<group>"; };
DE3568EB2C88F5BD00AF447C /* OneSignalExecutorMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneSignalExecutorMocks.swift; sourceTree = "<group>"; };
DE3568EF2C89067400AF447C /* SubscriptionsExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsExecutorTests.swift; sourceTree = "<group>"; };
DE3568F12C8911EA00AF447C /* IdentityExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityExecutorTests.swift; sourceTree = "<group>"; };
DE3CD2FE270FA9F200A5BECD /* OSOutcomes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OSOutcomes.m; sourceTree = "<group>"; };
DE51DDE3294262AB0073D5C4 /* OSRemoteParamController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OSRemoteParamController.m; sourceTree = "<group>"; };
DE51DDE4294262AB0073D5C4 /* OSRemoteParamController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSRemoteParamController.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2169,6 +2179,7 @@
3C87066F2BDE0957000D8CD2 /* MockUserRequests.swift */,
3C8706712BDEE076000D8CD2 /* MockUserDefines.swift */,
3CC063E52B6D7F96002BB07F /* OneSignalUserMocks.swift */,
DE3568EB2C88F5BD00AF447C /* OneSignalExecutorMocks.swift */,
);
path = OneSignalUserMocks;
sourceTree = "<group>";
Expand Down Expand Up @@ -2199,6 +2210,9 @@
isa = PBXGroup;
children = (
3CF11E3C2C6D6155002856F5 /* UserExecutorTests.swift */,
DE3568E92C88F56600AF447C /* PropertyExecutorTests.swift */,
DE3568EF2C89067400AF447C /* SubscriptionsExecutorTests.swift */,
DE3568F12C8911EA00AF447C /* IdentityExecutorTests.swift */,
);
path = Executors;
sourceTree = "<group>";
Expand Down Expand Up @@ -2492,6 +2506,7 @@
3CF8629F28A1964F00776CA4 /* OSPropertiesModel.swift */,
3CE795F828DB99B500736BD4 /* OSSubscriptionModelStoreListener.swift */,
3C5117162B15C31E00563465 /* OSUserState.swift */,
DE1DD05F2C87D87B00787071 /* OSJwtInvalidatedEvent.swift */,
);
path = Source;
sourceTree = "<group>";
Expand Down Expand Up @@ -4127,6 +4142,7 @@
3C8706702BDE0957000D8CD2 /* MockUserRequests.swift in Sources */,
3C8706722BDEE076000D8CD2 /* MockUserDefines.swift in Sources */,
3CC063E62B6D7F96002BB07F /* OneSignalUserMocks.swift in Sources */,
DE3568EC2C88F5BD00AF447C /* OneSignalExecutorMocks.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -4135,9 +4151,12 @@
buildActionMask = 2147483647;
files = (
3CF11E3D2C6D6155002856F5 /* UserExecutorTests.swift in Sources */,
DE3568EA2C88F56600AF447C /* PropertyExecutorTests.swift in Sources */,
DE3568F22C8911EA00AF447C /* IdentityExecutorTests.swift in Sources */,
3C67F77A2BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift in Sources */,
3CC063EE2B6D7FE8002BB07F /* OneSignalUserTests.swift in Sources */,
3CC890352C5BF9A7002CB4CC /* UserConcurrencyTests.swift in Sources */,
DE3568F02C89067400AF447C /* SubscriptionsExecutorTests.swift in Sources */,
3CDE664C2BFC2A56006DA114 /* OneSignalUserObjcTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -4286,6 +4305,7 @@
files = (
3CE795F928DB99B500736BD4 /* OSSubscriptionModelStoreListener.swift in Sources */,
DE69E1AC282ED87A0090BB3D /* OneSignalUserManagerImpl.swift in Sources */,
DE1DD0602C87D87B00787071 /* OSJwtInvalidatedEvent.swift in Sources */,
3C9AD6CF2B228B7800BC1540 /* OSRequestAddAliases.swift in Sources */,
3C9AD6D32B228BB000BC1540 /* OSRequestUpdateProperties.swift in Sources */,
3C9AD6CD2B228B6300BC1540 /* OSRequestFetchUser.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ - (void)initializeTriggerController {

- (void)updateInAppMessagesFromCache {
self.messages = [OneSignalUserDefaults.initStandard getSavedCodeableDataForKey:OS_IAM_MESSAGES_ARRAY defaultValue:[NSArray new]];
[self evaluateMessages];
// ECM THIS NEEDS TO RUN ON THE MAIN THREAD
dispatch_async(dispatch_get_main_queue(), ^{
[self evaluateMessages];
});
}

/**
Expand Down Expand Up @@ -323,11 +326,16 @@ - (void)getInAppMessagesFromServer {
OSResponseStatusType responseType = [OSNetworkingUtils getResponseStatusType:error.code];
if (responseType == OSResponseStatusUnauthorized) {
shouldRetryGetInAppMessagesOnJwtUpdated = true;
[self handleUnauthroizedError:error externalId:alias.id];
}
[self updateInAppMessagesFromCache];
}];
}

- (void)handleUnauthroizedError:(NSError*)error externalId:(NSString *)externalId {
[OneSignalUserManagerImpl.sharedInstance invalidateJwtForExternalIdWithExternalId:externalId error:error];
}

- (void)updateInAppMessagesFromServer:(NSArray<OSInAppMessageInternal *> *)newMessages {
[OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:@"updateInAppMessagesFromServer"];
self.messages = newMessages;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
// To simplify uncaching, we maintain separate request queues for each type
var addRequestQueue: [OSRequestAddAliases] = []
var removeRequestQueue: [OSRequestRemoveAlias] = []
var pendingAuthRequests: [String: [OSUserRequest]] = [String:[OSUserRequest]]()
let newRecordsState: OSNewRecordsState
let jwtConfig: OSUserJwtConfig

Expand Down Expand Up @@ -227,11 +228,39 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
}
}
}

func handleUnauthorizedError(externalId: String, error: NSError, request: OSUserRequest) {
if (jwtConfig.isRequired ?? false) {
self.pendRequestUntilAuthUpdated(request, externalId: externalId)
OneSignalUserManagerImpl.sharedInstance.invalidateJwtForExternalId(externalId: externalId, error: error)
}
}

func pendRequestUntilAuthUpdated(_ request: OSUserRequest, externalId: String?) {
self.dispatchQueue.async {
self.addRequestQueue.removeAll(where: { $0 == request})
self.removeRequestQueue.removeAll(where: { $0 == request})
guard let externalId = externalId else {
return
}
var requests = self.pendingAuthRequests[externalId] ?? []
let inQueue = requests.contains(where: {$0 == request})
guard !inQueue else {
return
}
requests.append(request)
self.pendingAuthRequests[externalId] = requests
}
}

func executeAddAliasesRequest(_ request: OSRequestAddAliases, inBackground: Bool) {
guard !request.sentToClient else {
return
}
guard request.addJWTHeaderIsValid(identityModel: request.identityModel) else {
pendRequestUntilAuthUpdated(request, externalId:request.identityModel.externalId)
return
}
guard request.prepareForExecution(newRecordsState: newRecordsState) else {
return
}
Expand Down Expand Up @@ -273,6 +302,11 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
// The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model
OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil
OneSignalUserManagerImpl.sharedInstance._logout()
} else if responseType == .unauthorized && (self.jwtConfig.isRequired ?? false) {
if let externalId = request.identityModel.externalId {
self.handleUnauthorizedError(externalId: externalId, error: nsError, request: request)
}
request.sentToClient = false
} else if responseType != .retryable {
// Fail, no retry, remove from cache and queue
self.addRequestQueue.removeAll(where: { $0 == request})
Expand All @@ -290,6 +324,10 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
guard !request.sentToClient else {
return
}
guard request.addJWTHeaderIsValid(identityModel: request.identityModel) else {
pendRequestUntilAuthUpdated(request, externalId:request.identityModel.externalId)
return
}
guard request.prepareForExecution(newRecordsState: newRecordsState) else {
return
}
Expand Down Expand Up @@ -317,7 +355,13 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
self.dispatchQueue.async {
if let nsError = error as? NSError {
let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code)
if responseType != .retryable {
if responseType == .unauthorized && (self.jwtConfig.isRequired ?? false) {
if let externalId = request.identityModel.externalId {
self.handleUnauthorizedError(externalId: externalId, error: nsError, request: request)
}
request.sentToClient = false
}
else if responseType != .retryable {
// Fail, no retry, remove from cache and queue
// A response of .missing could mean the alias doesn't exist on this user OR this user has been deleted
self.removeRequestQueue.removeAll(where: { $0 == request})
Expand All @@ -343,6 +387,26 @@ extension OSIdentityOperationExecutor: OSUserJwtConfigListener {

func onJwtUpdated(externalId: String, token: String?) {
print("❌ OSIdentityOperationExecutor onJwtUpdated for \(externalId) to \(String(describing: token))")
reQueuePendingRequestsForExternalId(externalId: externalId)
}

private func reQueuePendingRequestsForExternalId(externalId: String) {
self.dispatchQueue.async {
guard let requests = self.pendingAuthRequests[externalId] else {
return
}
for request in requests {
if let addRequest = request as? OSRequestAddAliases {
self.addRequestQueue.append(addRequest)
} else if let removeRequest = request as? OSRequestRemoveAlias {
self.removeRequestQueue.append(removeRequest)
}
}
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
self.pendingAuthRequests[externalId] = nil
self.processRequestQueue(inBackground: false)
}
}

private func removeInvalidDeltasAndRequests() {
Expand Down
Loading
Loading