Skip to content

Commit

Permalink
fixup: identity verification improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
jinliu9508 committed Nov 20, 2024
1 parent db78c39 commit 9d70a5c
Show file tree
Hide file tree
Showing 37 changed files with 204 additions and 310 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 @@ -144,9 +144,6 @@ public void onUserStateChange(@NonNull UserChangedState state) {
OneSignal.addUserJwtInvalidatedListner(new IUserJwtInvalidatedListener() {
@Override
public void onUserJwtInvalidated(@NonNull UserJwtInvalidatedEvent event) {
// !!! For manual testing only
String jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIwMTM5YmQ2Zi00NTFmLTQzOGMtODg4Ni00ZTBmMGZlM2EwODUiLCJleHAiOjE3MjczNjkyMjIsImlkZW50aXR5Ijp7ImV4dGVybmFsX2lkIjoiamluIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJ0eXBlIjoiU01TIiwidG9rZW4iOiIrMTIzNDU2NzgifSx7InR5cGUiOiJBbmRyb2lkUHVzaCIsImlkIjoiMTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDAwIn1dfQ.6XF7wRF4lLOvKr5Gd3MHv9j7U151hcBjmqSyk6nI6JVYUgt6q0YRp2j1aSJcg8VmaejzP1DouN1DpWUT_JTRXA";
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,8 +411,7 @@ private void setupAppLayout() {
@Override
public void onSuccess(String update) {
if (update != null && !update.isEmpty()) {
String jwt = "InitialJWT";
OneSignal.login(update, jwt);
OneSignal.login(update);
refreshState();
}
}
Expand Down Expand Up @@ -450,8 +449,6 @@ private void setupJWTLayout() {
public void onSuccess(String update) {
if (update != null && !update.isEmpty()) {
OneSignal.updateUserJwt(OneSignal.getUser().getExternalId(), update);
//String jwt = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxNjg4ZDhmMi1kYTdmLTQ4MTUtOGVlMy05ZDEzNzg4NDgyYzgiLCJpYXQiOjE3MTQwODA4MTMsImlkZW50aXR5Ijp7ImV4dGVybmFsX2lkIjoiMjAyNDA0MjUtYWxleDQyIn0sInN1YnNjcmlwdGlvbiI6W3sidHlwZSI6IiIsImlkIjoiMmRlZGU3MzItMTEyNi00MTlkLTk5M2UtNDIzYWQyYTZiZGU5In1dfQ.rzZ-HaDm1EwxbMxd8937bWzPhPSQDDSqSzaASgZZc5A5v8g6ZQHizN9CljOmoQ4lTLm7noD6rOmR07tlZdrI5w";
//OneSignal.login(update, jwt);
refreshState();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static boolean exists(Context context, String key) {
}

public static String getOneSignalAppId(Context context) {
return getSharedPreference(context).getString(OS_APP_ID_SHARED_PREF, "0139bd6f-451f-438c-8886-4e0f0fe3a085");
return getSharedPreference(context).getString(OS_APP_ID_SHARED_PREF, "77e32082-ea27-42e3-a898-c72e141824ef");
}

public static boolean getUserPrivacyConsent(Context context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ interface IOneSignal {
*/
val isInitialized: Boolean

/**
* Whether the security feature to authenticate your external user ids is enabled
*/
val useIdentityVerification: Boolean

/**
* The user manager for accessing user-scoped
* management.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.onesignal

/** TODO: complete the comment part for this listener
/**
* Implement this interface and provide an instance to [OneSignal.addUserJwtInvalidatedListner]
* in order to receive control when the JWT for the current user is invalidated.
*
* @see [User JWT Invalidated Event | OneSignal Docs](https://documentation.onesignal.com/docs/)
* @see [User JWT Invalidated Event | OneSignal Docs](https://documentation.onesignal.com/docs/identity-verification)
*/
interface IUserJwtInvalidatedListener {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,6 @@ object OneSignal {
val isInitialized: Boolean
get() = oneSignal.isInitialized

/**
* Whether the security feature to authenticate your external user ids is enabled
*/
@JvmStatic
val useIdentityVerification: Boolean
get() = oneSignal.useIdentityVerification

/**
* The current SDK version as a string.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.onesignal

/** TODO: jwt documentation
/**
* The event passed into [IUserJwtInvalidatedListener.onUserJwtInvalidated], it provides access
* to the external ID whose JWT has just been invalidated.
*
* For more information https://documentation.onesignal.com/docs/identity-verification#4-handle-jwt-lifecycle-events
*/
class UserJwtInvalidatedEvent(
val externalId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ import com.onesignal.core.internal.preferences.IPreferencesService
import com.onesignal.core.internal.preferences.impl.PreferencesService
import com.onesignal.core.internal.purchases.impl.TrackAmazonPurchase
import com.onesignal.core.internal.purchases.impl.TrackGooglePurchase
import com.onesignal.core.internal.startup.IBootstrapService
import com.onesignal.core.internal.startup.IStartableService
import com.onesignal.core.internal.time.ITime
import com.onesignal.core.internal.time.impl.Time
import com.onesignal.inAppMessages.IInAppMessagesManager
import com.onesignal.inAppMessages.internal.MisconfiguredIAMManager
import com.onesignal.internal.IdentityVerificationService
import com.onesignal.location.ILocationManager
import com.onesignal.location.internal.MisconfiguredLocationManager
import com.onesignal.notifications.INotificationsManager
Expand All @@ -59,6 +61,7 @@ internal class CoreModule : IModule {
builder.register<ConfigModelStore>().provides<ConfigModelStore>()
builder.register<ParamsBackendService>().provides<IParamsBackendService>()
builder.register<ConfigModelStoreListener>().provides<IStartableService>()
builder.register<IdentityVerificationService>().provides<IBootstrapService>()

// Operations
builder.register<OperationModelStore>().provides<OperationModelStore>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,39 +46,29 @@ internal class HttpClient(
url: String,
body: JSONObject,
headers: OptionalHeaders?,
): HttpResponse {
return makeRequest(url, "POST", body, _configModelStore.model.httpTimeout, headers)
}
): HttpResponse = makeRequest(url, "POST", body, _configModelStore.model.httpTimeout, headers)

override suspend fun get(
url: String,
headers: OptionalHeaders?,
): HttpResponse {
return makeRequest(url, null, null, _configModelStore.model.httpGetTimeout, headers)
}
): HttpResponse = makeRequest(url, null, null, _configModelStore.model.httpGetTimeout, headers)

override suspend fun put(
url: String,
body: JSONObject,
headers: OptionalHeaders?,
): HttpResponse {
return makeRequest(url, "PUT", body, _configModelStore.model.httpTimeout, headers)
}
): HttpResponse = makeRequest(url, "PUT", body, _configModelStore.model.httpTimeout, headers)

override suspend fun patch(
url: String,
body: JSONObject,
headers: OptionalHeaders?,
): HttpResponse {
return makeRequest(url, "PATCH", body, _configModelStore.model.httpTimeout, headers)
}
): HttpResponse = makeRequest(url, "PATCH", body, _configModelStore.model.httpTimeout, headers)

override suspend fun delete(
url: String,
headers: OptionalHeaders?,
): HttpResponse {
return makeRequest(url, "DELETE", null, _configModelStore.model.httpTimeout, headers)
}
): HttpResponse = makeRequest(url, "DELETE", null, _configModelStore.model.httpTimeout, headers)

private suspend fun makeRequest(
url: String,
Expand Down Expand Up @@ -151,15 +141,10 @@ internal class HttpClient(
con.setRequestProperty("SDK-Version", "onesignal/android/" + OneSignalUtils.SDK_VERSION)

val jwt = headers?.jwt
if (!jwt.isNullOrEmpty()) {
if (jwt != null) {
con.setRequestProperty("Authorization", "Bearer $jwt")
}

val deviceAuthPushToken = headers?.deviceAuthPushToken
if (_configModelStore.model.useIdentityVerification && !deviceAuthPushToken.isNullOrEmpty()) {
con.setRequestProperty("Device-Auth-Push-Token", "Basic $deviceAuthPushToken")
}

if (OneSignalWrapper.sdkType != null && OneSignalWrapper.sdkVersion != null) {
con.setRequestProperty("SDK-Wrapper", "onesignal/${OneSignalWrapper.sdkType}/${OneSignalWrapper.sdkVersion}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ internal class HttpConnectionFactory(
) : IHttpConnectionFactory {
@Throws(IOException::class)
override fun newHttpURLConnection(url: String): HttpURLConnection {
return URL("https://staging.onesignal.com/api/v1/" + url).openConnection() as HttpURLConnection
return URL(_configModelStore.model.apiUrl + url).openConnection() as HttpURLConnection
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ data class OptionalHeaders(
*/
val sessionDuration: Long? = null,
val jwt: String? = null,
val deviceAuthPushToken: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ interface IOperationRepo {
suspend fun awaitInitialized()

fun forceExecuteOperations()

fun setPaused(paused: Boolean)
}

// Extension function so the syntax containsInstanceOf<Operation>() can be used over
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ internal class OperationRepo(
coroutineScope.launch {
// load saved operations first then start processing the queue to ensure correct operation order
loadSavedOperations()
paused = false
processQueueForever()
}
}
Expand Down Expand Up @@ -191,10 +190,6 @@ internal class OperationRepo(
waiter.wake(LoopWaiterMessage(false))
}

override fun setPaused(paused: Boolean) {
this.paused = paused
}

/**
* Waits until a new operation is enqueued, then wait an additional
* amount of time afterwards, so operations can be grouped/batched.
Expand Down Expand Up @@ -270,6 +265,8 @@ internal class OperationRepo(
}
ExecutionResult.FAIL_UNAUTHORIZED -> {
Logging.error("Operation execution failed with invalid jwt")
_identityModelStore.invalidateJwt()

// 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 @@ -359,31 +356,20 @@ internal class OperationRepo(

internal fun getNextOps(bucketFilter: Int): List<OperationQueueItem>? {
return synchronized(queue) {
var startingOp: OperationQueueItem? = null
// Search for the first operation that is qualified to execute
for (queueItem in queue) {
val operation = queueItem.operation

// Ensure the operation is in an executable state
if (!operation.canStartExecute ||
!_newRecordState.canAccess(
operation.applyToRecordId,
) || queueItem.bucket > bucketFilter
) {
continue
}
// Ensure the operation does not have empty JWT if identity verification is on
if (_configModelStore.model.useIdentityVerification &&
_identityModelStore.model.jwtToken == null
) {
return null
}

// Ensure the operation does not have empty JWT if identity verification is on
if (_configModelStore.model.useIdentityVerification &&
_identityModelStore.model.jwtToken.isNullOrEmpty()
) {
continue
val startingOp =
queue.firstOrNull {
it.operation.canStartExecute &&
_newRecordState.canAccess(it.operation.applyToRecordId) &&
it.bucket <= bucketFilter
}

startingOp = queueItem
break
}

if (startingOp != null) {
queue.remove(startingOp)
getGroupableOperations(startingOp)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.onesignal.internal

import com.onesignal.core.internal.backend.ParamsObject
import com.onesignal.core.internal.config.ConfigModelStore
import com.onesignal.core.internal.config.FetchParamsObserver
import com.onesignal.core.internal.operations.IOperationRepo
import com.onesignal.core.internal.startup.IBootstrapService
import com.onesignal.debug.LogLevel
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.user.internal.identity.IdentityModelStore
import com.onesignal.user.internal.operations.LoginUserOperation

internal class IdentityVerificationService(
private val _configModelStore: ConfigModelStore,
private val _identityModelStore: IdentityModelStore,
private val opRepo: IOperationRepo,
) : IBootstrapService {
override fun bootstrap() {
_configModelStore.model.addFetchParamsObserver(
object : FetchParamsObserver {
override fun onParamsFetched(params: ParamsObject) {
if (params.useIdentityVerification == true && _identityModelStore.model.jwtToken == null) {
Logging.log(LogLevel.INFO, "A valid JWT is required for user ${_identityModelStore.model.externalId}.")
return
}

// calling login either identity verification is turned off or a jwt is cached
opRepo.enqueue(
LoginUserOperation(
_configModelStore.model.appId,
_identityModelStore.model.onesignalId,
_identityModelStore.model.externalId,
),
)
}
},
)
}
}
Loading

0 comments on commit 9d70a5c

Please sign in to comment.