Skip to content

Commit

Permalink
Init behavior change based on identity verification
Browse files Browse the repository at this point in the history
  • Loading branch information
jinliu9508 committed Oct 11, 2024
1 parent a913146 commit 0549687
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void onCreate() {
// This will reproduce result similar to Kotlin CouroutineScope.launch{}, which may potentially crash the app
ExecutorService executor = Executors.newSingleThreadExecutor();
@SuppressLint({"NewApi", "LocalSuppress"}) CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
OneSignal.getNotifications().requestPermission(true, Continue.none());
//OneSignal.getNotifications().requestPermission(true, Continue.none());
}, executor);
future.join(); // Waits for the task to complete
executor.shutdown();
Expand Down Expand Up @@ -145,7 +145,7 @@ public void onUserStateChange(@NonNull UserChangedState state) {
@Override
public void onUserJwtInvalidated(@NonNull UserJwtInvalidatedEvent event) {
// !!! For manual testing only
String jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxNjg4ZDhmMi1kYTdmLTQ4MTUtOGVlMy05ZDEzNzg4NDgyYzgiLCJpYXQiOjE3MTgzMDk5NzIsImlkZW50aXR5Ijp7ImV4dGVybmFsX2lkIjoiYWxleC0wNjE0Iiwib25lc2lnbmFsX2lkIjoiYTViYjc4NDYtYzExNC00YzdkLTkzMWYtNGQ0NjhiMGE5OWJhIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJpZCI6ImE2YzQxNmY3LTMxMGUtNDgzNi05Yjc4LWZiZmQ5NTgyNWNjNCJ9XX0.HsjsA2qNPwd9qov_8Px01km-dzRug-YKNNG85cMrGYI9Pdb2uoPQSdAN3Uqu7_o4pL8FRxXliYJrC52-9wH3FQ";
String jwt = "SecondJWT";
OneSignal.updateUserJwt(event.getExternalId(), jwt);
Log.v(Tag.LOG_TAG, "onUserJwtInvalidated fired with ID:" + event.getExternalId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ private void setupAppLayout() {
@Override
public void onSuccess(String update) {
if (update != null && !update.isEmpty()) {
String jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxNjg4ZDhmMi1kYTdmLTQ4MTUtOGVlMy05ZDEzNzg4NDgyYzgiLCJpYXQiOjE3MTU5NzMwNzAsImlkZW50aXR5Ijp7ImV4dGVybmFsX2lkIjoiYWxleC0wNTE3Iiwib25lc2lnbmFsX2lkIjoiMGIzYWMyN2EtYWQ4Yi00MWVjLWJhYTYtMzI0NmNkODIyMjJkIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoiYWxleHRzYXktMDUxN0BvbmVzaWduYWwuY29tIn0seyJ0eXBlIjoiQW5kcm9pZFB1c2giLCJpZCI6ImFkMTAxY2FjLTA5MWItNDkyYy04OGJiLTgxNmZkNTNjYTBmMSJ9XX0._tlD2X8J16gDkP7__FJ8CwpqCLDwb8T14m2ugJwQvuQqbIn4b8o75cKbffbjVGcKP3YaudLCebit53aR9LTQCw";
String jwt = "InitialJWT";
OneSignal.login(update, jwt);
refreshState();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.onesignal.core.internal.startup.IStartableService
import com.onesignal.core.internal.time.ITime
import com.onesignal.debug.LogLevel
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.user.internal.backend.IdentityConstants
import com.onesignal.user.internal.identity.IdentityModelStore
import com.onesignal.user.internal.operations.impl.states.NewRecordsState
import kotlinx.coroutines.CompletableDeferred
Expand Down Expand Up @@ -97,10 +96,10 @@ internal class OperationRepo(
}

override fun start() {
paused = false
coroutineScope.launch {
// load saved operations first then start processing the queue to ensure correct operation order
loadSavedOperations()
paused = false
processQueueForever()
}
}
Expand Down Expand Up @@ -270,9 +269,7 @@ internal class OperationRepo(
ops.forEach { it.waiter?.wake(true) }
}
ExecutionResult.FAIL_UNAUTHORIZED -> {
Logging.error("Operation execution failed with invalid jwt, pausing the operation repo: $operations")
// keep the failed operation and pause the operation repo from executing
paused = true
Logging.error("Operation execution failed with invalid jwt")
// add back all operations to the front of the queue to be re-executed.
synchronized(queue) {
ops.reversed().forEach { queue.add(0, it) }
Expand Down Expand Up @@ -378,7 +375,6 @@ internal class OperationRepo(

// Ensure the operation does not have empty JWT if identity verification is on
if (_configModelStore.model.useIdentityVerification &&
operation.hasProperty(IdentityConstants.EXTERNAL_ID) &&
_identityModelStore.model.jwtToken.isNullOrEmpty()
) {
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
)
if (legacyPlayerId == null) {
Logging.debug("initWithContext: creating new device-scoped user")
createAndSwitchToNewUser()
operationRepo!!.enqueue(
LoginUserOperation(
configModel!!.appId,
identityModelStore!!.model.onesignalId,
identityModelStore!!.model.externalId,
),
)
createAndSwitchToNewUser(suppressBackendOperation = true)
} else {
Logging.debug("initWithContext: creating user linked to subscription $legacyPlayerId")

Expand Down Expand Up @@ -317,7 +310,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
suppressBackendOperation = true
}

createAndSwitchToNewUser(suppressBackendOperation = suppressBackendOperation)
createAndSwitchToNewUser(suppressBackendOperation = true)

// ** No longer allowed when identity verification is on
operationRepo!!.enqueue(
Expand Down Expand Up @@ -372,7 +365,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
}

// TODO: Set JWT Token for all future requests.
createAndSwitchToNewUser { identityModel, _ ->
createAndSwitchToNewUser(suppressBackendOperation = false) { identityModel, _ ->
identityModel.externalId = externalId
identityModel.jwtToken = jwtBearerToken
}
Expand All @@ -388,17 +381,31 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
// time if network conditions prevent the operation to succeed. This allows us to
// provide a callback to the caller when we can absolutely say the user is logged
// in, so they may take action on their own backend.

val result =
operationRepo!!.enqueueAndWait(
LoginUserOperation(
configModel!!.appId,
newIdentityOneSignalId,
externalId,
if (currentIdentityExternalId == null) currentIdentityOneSignalId else null,
),
)

if (!result) {
when (useIdentityVerification) {
true -> {
operationRepo!!.enqueue(
LoginUserOperation(
configModel!!.appId,
identityModelStore!!.model.onesignalId,
identityModelStore!!.model.externalId,
),
)
}
else -> {
operationRepo!!.enqueueAndWait(
LoginUserOperation(
configModel!!.appId,
newIdentityOneSignalId,
externalId,
if (currentIdentityExternalId == null) currentIdentityOneSignalId else null,
),
)
}
}

if (result == false) {
Logging.log(LogLevel.ERROR, "Could not login user")
}
}
Expand Down Expand Up @@ -437,7 +444,6 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
for (model in identityModelStore!!.store.list()) {
if (externalId == model.externalId) {
identityModelStore!!.model.jwtToken = token
operationRepo!!.setPaused(false)
operationRepo!!.forceExecuteOperations()
Logging.log(LogLevel.DEBUG, "JWT $token is updated for externalId $externalId")
return
Expand Down Expand Up @@ -476,6 +482,20 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
modify(identityModel, propertiesModel)
}

if (!identityModel.jwtToken.isNullOrEmpty()) {
setupNewSubscription(identityModel, propertiesModel, suppressBackendOperation, sdkId)
}

identityModelStore!!.replace(identityModel)
propertiesModelStore!!.replace(propertiesModel)
}

private fun setupNewSubscription(
identityModel: IdentityModel,
propertiesModel: PropertiesModel,
suppressBackendOperation: Boolean,
sdkId: String,
) {
val subscriptions = mutableListOf<SubscriptionModel>()

// Create the push subscription for this device under the new user, copying the current
Expand All @@ -484,7 +504,7 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
// will be automatically transferred over to this new user being created. If there is no
// current push subscription we do a "normal" replace which will drive adding a CreateSubscriptionOperation
// to the queue.
val currentPushSubscription = subscriptionModelStore!!.list().firstOrNull { it.id == configModel!!.pushSubscriptionId }
val currentPushSubscription = subscriptionModelStore!!.list().firstOrNull { it.type == SubscriptionType.PUSH }
val newPushSubscription = SubscriptionModel()

newPushSubscription.id = currentPushSubscription?.id ?: IDManager.createLocalId()
Expand Down Expand Up @@ -512,7 +532,13 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {

if (suppressBackendOperation) {
subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE)
} else if (currentPushSubscription != null) {
} else if (currentPushSubscription != null && (
!useIdentityVerification || useIdentityVerification &&
!IDManager.isLocalId(
currentPushSubscription.id,
)
)
) {
operationRepo!!.enqueue(TransferSubscriptionOperation(configModel!!.appId, currentPushSubscription.id, sdkId))
subscriptionModelStore!!.replaceAll(subscriptions, ModelChangeTags.NO_PROPOGATE)
} else {
Expand All @@ -521,14 +547,18 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
}

private fun resumeOperationRepoAfterFetchParams(configModel: ConfigModel) {
// pause operation repo until useIdentityVerification is determined
operationRepo!!.setPaused(true)
configModel.addFetchParamsObserver(
object : FetchParamsObserver {
override fun onParamsFetched(params: ParamsObject) {
// resume operations if identity verification is turned off or a jwt is cached
if (params.useIdentityVerification == false || identityModelStore!!.model.jwtToken != null) {
operationRepo!!.setPaused(false)
operationRepo!!.enqueue(
LoginUserOperation(
configModel!!.appId,
identityModelStore!!.model.onesignalId,
identityModelStore!!.model.externalId,
),
)
} else {
Logging.log(LogLevel.ERROR, "A valid JWT is required for user ${identityModelStore!!.model.externalId}.")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ internal open class UserManager(
// prevent same JWT from being invalidated twice in a row
if (OneSignal.useIdentityVerification && jwtTokenInvalidated != oldJwt && newJwt.isEmpty()) {
jwtInvalidatedCallback.fire {
it.onUserJwtInvalidated(UserJwtInvalidatedEvent((externalId)))
it.onUserJwtInvalidated(UserJwtInvalidatedEvent(externalId))
}
}

Expand Down

0 comments on commit 0549687

Please sign in to comment.