Skip to content

Commit

Permalink
Merge pull request #1488 from OneSignal/identity_verification_logout
Browse files Browse the repository at this point in the history
[JWT] Handle logout when Identity verification is on
  • Loading branch information
nan-li authored Oct 4, 2024
2 parents 7d5db5e + 0a81b7a commit 1e7bce1
Show file tree
Hide file tree
Showing 20 changed files with 377 additions and 139 deletions.
4 changes: 2 additions & 2 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
return YES;
}

#define ONESIGNAL_APP_ID_DEFAULT @"0139bd6f-451f-438c-8886-4e0f0fe3a085"
#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"0139bd6f-451f-438c-8886-4e0f0fe3a085"
#define ONESIGNAL_APP_ID_DEFAULT @"77e32082-ea27-42e3-a898-c72e141824ef"
#define ONESIGNAL_APP_ID_KEY_FOR_TESTING @"77e32082-ea27-42e3-a898-c72e141824ef"

+ (NSString*)getOneSignalAppId {
NSString* userDefinedAppId = [[NSUserDefaults standardUserDefaults] objectForKey:ONESIGNAL_APP_ID_KEY_FOR_TESTING];
Expand Down
4 changes: 2 additions & 2 deletions iOS_SDK/OneSignalDevApp/OneSignalDevApp/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,14 @@ - (IBAction)inAppMessagingSegmentedControlValueChanged:(UISegmentedControl *)sen
- (IBAction)loginExternalUserId:(UIButton *)sender {
NSString* externalUserId = self.externalUserIdTextField.text;
NSString* token = self.tokenTextField.text;
NSLog(@"Dev App: Logging in to external user ID %@ and token %@", externalUserId, token);
NSLog(@"Dev App: Logging in to external user ID %@ and token %@", externalUserId, token);
[OneSignal login:externalUserId withToken:token];
}

- (IBAction)updateJwt:(id)sender {
NSString* externalUserId = self.externalUserIdTextField.text;
NSString* token = self.tokenTextField.text;
NSLog(@"Dev App: updating JWT for external user ID %@ and token %@", externalUserId, token);
NSLog(@"Dev App: updating JWT for external user ID %@ and token %@", externalUserId, token);
[OneSignal updateUserJwt:externalUserId withToken:token];
}

Expand Down
227 changes: 221 additions & 6 deletions iOS_SDK/OneSignalDevApp/OneSignalExample.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
// Networking
#define OS_API_VERSION @"1"
#define OS_API_ACCEPT_HEADER @"application/vnd.onesignal.v" OS_API_VERSION @"+json"
#define OS_API_SERVER_URL @"https://api.staging.onesignal.com/"
#define OS_IAM_WEBVIEW_BASE_URL @"https://staging.onesignal.com/"
#define OS_API_SERVER_URL @"https://api.onesignal.com/"
#define OS_IAM_WEBVIEW_BASE_URL @"https://onesignal.com/"

// OneSignalUserDefault keys
// String values start with "OSUD_" to maintain a level of uniqueness from other libs and app code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ + (OSUIApplicationReleaseMode) releaseMode {
NSDictionary *entitlements = nil;
NSDictionary *provision = [self getProvision];
if (provision) {
// [OneSignalLog onesignalLog:ONE_S_LL_DEBUG message:[NSString stringWithFormat:@"provision: %@", provision]];
[OneSignalLog onesignalLog:ONE_S_LL_DEBUG message:[NSString stringWithFormat:@"provision: %@", provision]];
entitlements = [provision objectForKey:@"Entitlements"];
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1154,7 +1154,6 @@ - (void)onPushSubscriptionDidChangeWithState:(OSPushSubscriptionChangedState * _

#pragma mark OSUserStateObserver Methods
- (void)onUserStateDidChangeWithState:(OSUserChangedState * _Nonnull)state {
NSLog(@"❌ OSMessagingController onUserStateDidChangeWithState: %@", [state jsonRepresentation]);
if (state.current.onesignalId && shouldRetryGetInAppMessagesOnUserChange) {
shouldRetryGetInAppMessagesOnUserChange = false;
[self getInAppMessagesFromServer];
Expand All @@ -1167,7 +1166,6 @@ - (void)onRequiresUserAuthChangedFrom:(enum OSRequiresUserAuth)from to:(enum OSR
}

- (void)onJwtUpdatedWithExternalId:(NSString *)externalId token:(NSString *)token {
NSLog(@"❌ OSMessagingController onJwtUpdatedWithExternalId: %@ token: %@", externalId, token);
if (![token isEqual: OS_JWT_TOKEN_INVALID] && shouldRetryGetInAppMessagesOnJwtUpdated) {
shouldRetryGetInAppMessagesOnJwtUpdated = false;
[self getInAppMessagesFromServer];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ public class OSUserJwtConfig {
return
}

print("❌ OSUserJwtConfig.requiresUserAuth: changing from \(oldValue) to \(requiresUserAuth), firing \(changeNotifier)")

OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSUserJwtConfig.requiresUserAuth: changing from \(oldValue) to \(requiresUserAuth), firing listeners")
// Persist new value
OneSignalUserDefaults.initShared().saveInteger(forKey: OSUD_USE_IDENTITY_VERIFICATION, withValue: requiresUserAuth.rawValue)

Expand Down Expand Up @@ -93,9 +92,6 @@ public class OSUserJwtConfig {

public init() {
let rawValue = OneSignalUserDefaults.initShared().getSavedInteger(forKey: OSUD_USE_IDENTITY_VERIFICATION, defaultValue: OSRequiresUserAuth.unknown.rawValue)

print("❌ OSUserJwtConfig init(): \(String(describing: OSRequiresUserAuth(rawValue: rawValue))))")

requiresUserAuth = OSRequiresUserAuth(rawValue: rawValue) ?? OSRequiresUserAuth.unknown
}

Expand All @@ -104,7 +100,7 @@ public class OSUserJwtConfig {
}

public func onJwtTokenChanged(externalId: String, token: String?) {
print("OSUserJwtConfig.onJwtTokenChanged \(externalId): \(token)")
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSUserJwtConfig.onJwtTokenChanged for \(externalId) with token \(token ?? "nil"), firing listeners")
changeNotifier.fire { listener in
listener.onJwtUpdated(externalId: externalId, token: token)
}
Expand Down
18 changes: 10 additions & 8 deletions iOS_SDK/OneSignalSDK/OneSignalOSCore/Source/OSOperationRepo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ public class OSOperationRepo {
public init(jwtConfig: OSUserJwtConfig) {
self.jwtConfig = jwtConfig
self.jwtConfig.subscribe(self, key: OS_OPERATION_REPO)
print("❌ OSOperationRepo init(\(String(describing: jwtConfig.isRequired))) called")

// Read the Deltas from cache, if any...
guard let deltaQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_OPERATION_REPO_DELTA_QUEUE_KEY, defaultValue: []) as? [OSDelta] else {
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSOperationRepo is unable to uncache the OSDelta queue.")
Expand All @@ -73,7 +71,7 @@ public class OSOperationRepo {
}

guard jwtConfig.isRequired != nil else {
print("OSOperationRepo.start() returning early due to unknown Identity Verification status.")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "OSOperationRepo.start() returning early due to unknown Identity Verification status")
return
}

Expand Down Expand Up @@ -185,7 +183,6 @@ public class OSOperationRepo {

extension OSOperationRepo: OSUserJwtConfigListener {
public func onRequiresUserAuthChanged(from: OSRequiresUserAuth, to: OSRequiresUserAuth) {
print("❌ OSOperationRepo onRequiresUserAuthChanged from \(String(describing: from)) to \(String(describing: to))")
// If auth changed from false or unknown to true, process deltas
if to == .on {
removeInvalidDeltas()
Expand All @@ -194,7 +191,7 @@ extension OSOperationRepo: OSUserJwtConfigListener {
}

public func onJwtUpdated(externalId: String, token: String?) {
print("❌ OSOperationRepo onJwtUpdated for \(externalId) to \(String(describing: token))")
// Not used for now
}

/**
Expand All @@ -203,14 +200,19 @@ extension OSOperationRepo: OSUserJwtConfigListener {
Executors will handle this.
*/
func removeInvalidDeltas() {
print("❌ OSOperationRepo removeInvalidDeltas TODO!")
// Not used for now
}
}

extension OSOperationRepo: OSLoggable {
public func logSelf() {
print("💛 Operation Repo: deltaQueue: \(self.deltaQueue )")
print("💛 Operation Repo: executors that are subscribed:")
OneSignalLog.onesignalLog(.LL_VERBOSE, message:
"""
Operation Repo: deltaQueue: \(self.deltaQueue)
Operation Repo: executors that are subscribed:
"""
)
for executor in self.executors {
executor.logSelf()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class OSIdentityOperationExecutor: OSOperationExecutor {
self.newRecordsState = newRecordsState
self.jwtConfig = jwtConfig
self.jwtConfig.subscribe(self, key: OS_IDENTITY_EXECUTOR)
print("❌ OSIdentityOperationExecutor init(\(jwtConfig.isRequired))")
// Read unfinished deltas and requests from cache, if any...
uncacheDeltas()
uncacheRequests()
Expand Down Expand Up @@ -206,7 +205,7 @@ class OSIdentityOperationExecutor: OSOperationExecutor {

// If JWT is on but the external ID does not exist, drop this Delta
if self.jwtConfig.isRequired == true, model.externalId == nil {
print("\(delta) is Invalid with JWT, being dropped")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSIdentityOperationExecutor.processDeltaQueue dropped \(delta)")
}

switch delta.name {
Expand Down Expand Up @@ -401,15 +400,13 @@ class OSIdentityOperationExecutor: OSOperationExecutor {

extension OSIdentityOperationExecutor: OSUserJwtConfigListener {
func onRequiresUserAuthChanged(from: OSRequiresUserAuth, to: OSRequiresUserAuth) {
print("❌ OSIdentityOperationExecutor onUserAuthChanged from \(String(describing: from)) to \(String(describing: to))")
// If auth changed from false or unknown to true, process requests
if to == .on {
removeInvalidDeltasAndRequests()
}
}

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

Expand All @@ -435,26 +432,25 @@ extension OSIdentityOperationExecutor: OSUserJwtConfigListener {

private func removeInvalidDeltasAndRequests() {
self.dispatchQueue.async {
print("❌ OSIdentityOperationExecutor.removeInvalidDeltasAndRequests called")
for (index, delta) in self.deltaQueue.enumerated().reversed() {
if (delta.model as? OSIdentityModel)?.externalId == nil {
print(" \(delta) is Invalid, being removed")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSIdentityOperationExecutor.removeInvalidDeltasAndRequests dropped \(delta)")
self.deltaQueue.remove(at: index)
}
}
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_DELTA_QUEUE_KEY, withValue: self.deltaQueue)

for (index, request) in self.addRequestQueue.enumerated().reversed() {
if request.identityModel.externalId == nil {
print(" \(request) is Invalid, being removed")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSIdentityOperationExecutor.removeInvalidDeltasAndRequests dropped \(request)")
self.addRequestQueue.remove(at: index)
}
}
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)

for (index, request) in self.removeRequestQueue.enumerated().reversed() {
if request.identityModel.externalId == nil {
print(" \(request) is Invalid, being removed")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSIdentityOperationExecutor.removeInvalidDeltasAndRequests dropped \(request)")
self.removeRequestQueue.remove(at: index)
}
}
Expand All @@ -465,13 +461,14 @@ extension OSIdentityOperationExecutor: OSUserJwtConfigListener {

extension OSIdentityOperationExecutor: OSLoggable {
func logSelf() {
print(
OneSignalLog.onesignalLog(.LL_VERBOSE, message:
"""
💛 OSIdentityOperationExecutor has the following queues:
OSIdentityOperationExecutor has the following queues:
addRequestQueue: \(self.addRequestQueue)
removeRequestQueue: \(self.removeRequestQueue)
deltaQueue: \(self.deltaQueue)
pendingAuthRequests: \(self.pendingAuthRequests)
"""
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,13 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
self.newRecordsState = newRecordsState
self.jwtConfig = jwtConfig
self.jwtConfig.subscribe(self, key: OS_PROPERTIES_EXECUTOR)
print("❌ OSPropertyOperationExecutor init(\(String(describing: jwtConfig.isRequired)))")

// Read unfinished deltas and requests from cache, if any...
// Note that we should only have deltas for the current user as old ones are flushed..
uncacheDeltas()
uncacheUpdateRequests()
}

private func uncacheDeltas() {
print("❌ OSPropertyOperationExecutor uncacheDeltas called")

if var deltaQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_PROPERTIES_EXECUTOR_DELTA_QUEUE_KEY, defaultValue: []) as? [OSDelta] {
for (index, delta) in deltaQueue.enumerated().reversed() {
guard let model = OneSignalUserManagerImpl.sharedInstance.getIdentityModel(delta.identityModelId) else {
Expand All @@ -97,7 +93,7 @@ class OSPropertyOperationExecutor: OSOperationExecutor {

// If JWT is on but the external ID does not exist, drop this Delta
if jwtConfig.isRequired == true, model.externalId == nil {
print("❌ removing \(delta)")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSPropertyOperationExecutor.uncacheDeltas dropped \(delta)")
deltaQueue.remove(at: index)
}
}
Expand All @@ -106,7 +102,6 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
} else {
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSPropertyOperationExecutor error encountered reading from cache for \(OS_PROPERTIES_EXECUTOR_DELTA_QUEUE_KEY)")
}
print("❌ OSPropertyOperationExecutor uncacheDeltas done, \(self.deltaQueue)")
}

private func uncacheUpdateRequests() {
Expand All @@ -117,15 +112,13 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
}

if let pendingRequests = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_PROPERTIES_EXECUTOR_PENDING_QUEUE_KEY, defaultValue: [:]) as? [String: [OSRequestUpdateProperties]] {
print("❌ prop executor uncached pending \(pendingRequests)")

for requests in pendingRequests.values {
for request in requests {
updateRequestQueue.append(request)
}
}
}
print("❌ prop executor uncached requests \(updateRequestQueue)")

// Hook each uncached Request to the model in the store
for (index, request) in updateRequestQueue.enumerated().reversed() {
if jwtConfig.isRequired == true,
Expand Down Expand Up @@ -172,7 +165,7 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
*/
func processDeltaQueue(inBackground: Bool) {
guard jwtConfig.isRequired != nil else {
print("OSPropertyOperationExecutor processDeltaQueue returning early due to requiresAuth: \(String(describing: jwtConfig.isRequired))")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "OSPropertyOperationExecutor processDeltaQueue returning early due to requiresAuth: \(String(describing: jwtConfig.isRequired))")
return
}

Expand All @@ -198,7 +191,7 @@ class OSPropertyOperationExecutor: OSOperationExecutor {

// If JWT is on but the external ID does not exist, drop this Delta
if self.jwtConfig.isRequired == true, identityModel.externalId == nil {
print("\(delta) is Invalid with JWT, being dropped")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSPropertyOperationExecutor.processDeltaQueue dropped \(delta)")
}

let combinedSoFar: OSCombinedProperties? = combinedProperties[identityModel.modelId]
Expand Down Expand Up @@ -317,7 +310,6 @@ class OSPropertyOperationExecutor: OSOperationExecutor {
return
}

print("ECM executing properties request: %@", request.identityModel.externalId)
request.sentToClient = true

let backgroundTaskIdentifier = PROPERTIES_EXECUTOR_BACKGROUND_TASK + UUID().uuidString
Expand Down Expand Up @@ -375,15 +367,13 @@ class OSPropertyOperationExecutor: OSOperationExecutor {

extension OSPropertyOperationExecutor: OSUserJwtConfigListener {
func onRequiresUserAuthChanged(from: OSRequiresUserAuth, to: OSRequiresUserAuth) {
print("❌ OSPropertyOperationExecutor onUserAuthChanged from \(String(describing: from)) to \(String(describing: to))")
// If auth changed from false or unknown to true, process requests
if to == .on {
removeInvalidDeltasAndRequests()
}
}

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

Expand All @@ -404,21 +394,19 @@ extension OSPropertyOperationExecutor: OSUserJwtConfigListener {

private func removeInvalidDeltasAndRequests() {
self.dispatchQueue.async {
print("❌ OSPropertyOperationExecutor.removeInvalidDeltasAndRequests called")

for (index, delta) in self.deltaQueue.enumerated().reversed() {
if let identityModel = OneSignalUserManagerImpl.sharedInstance.getIdentityModel(delta.identityModelId),
identityModel.externalId == nil
{
print(" \(delta) is Invalid, being removed")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSPropertyOperationExecutor.removeInvalidDeltasAndRequests dropped \(delta)")
self.deltaQueue.remove(at: index)
}
}
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_DELTA_QUEUE_KEY, withValue: self.deltaQueue)

for (index, request) in self.updateRequestQueue.enumerated().reversed() {
if request.identityModel.externalId == nil {
print(" \(request) is Invalid, being removed")
OneSignalLog.onesignalLog(.LL_DEBUG, message: "Invalid with JWT: OSPropertyOperationExecutor.removeInvalidDeltasAndRequests dropped \(request)")
self.updateRequestQueue.remove(at: index)
}
}
Expand All @@ -429,12 +417,13 @@ extension OSPropertyOperationExecutor: OSUserJwtConfigListener {

extension OSPropertyOperationExecutor: OSLoggable {
func logSelf() {
print(
OneSignalLog.onesignalLog(.LL_VERBOSE, message:
"""
💛 OSPropertyOperationExecutor has the following queues:
OSPropertyOperationExecutor has the following queues:
updateRequestQueue: \(self.updateRequestQueue)
deltaQueue: \(self.deltaQueue)
pendingAuthRequests: \(self.pendingAuthRequests)
"""
)
}
Expand Down
Loading

0 comments on commit 1e7bce1

Please sign in to comment.