From 099e567ad41fa9a26f127aeab45c06fa330c6c35 Mon Sep 17 00:00:00 2001 From: Shcherbynskyi Bohdan <132656146+bohdan-go-wombat@users.noreply.github.com> Date: Wed, 1 Nov 2023 12:00:07 +0200 Subject: [PATCH] [DIA-2654] Flush data if authId or propertyId changes (#711) --- .../cmplibrary/campaign/CampaignManager.kt | 42 ++++++++-- .../cmplibrary/data/ServiceImpl.kt | 7 +- .../cmplibrary/data/local/DataStorage.kt | 3 + .../cmplibrary/data/local/DataStorageImpl.kt | 8 ++ .../v6/MainActivityKotlinOldConsentTest.kt | 4 +- .../app/v6/MainActivityKotlinTest.kt | 83 ++++++++++++++++++- .../java/com/sourcepoint/app/v6/TestData.kt | 48 ++++++++++- 7 files changed, 182 insertions(+), 13 deletions(-) diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/campaign/CampaignManager.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/campaign/CampaignManager.kt index 1e906f9bd..d21bff837 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/campaign/CampaignManager.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/campaign/CampaignManager.kt @@ -88,7 +88,9 @@ internal interface CampaignManager { var choiceResp: ChoiceResp? var dataRecordedConsent: Instant? var authId: String? + var propertyId: Int + fun handleAuthIdOrPropertyIdChange(newAuthId: String?, newPropertyId: Int) fun handleMetaDataResponse(response: MetaDataResp?) fun handleOldLocalData() fun getGdprPvDataBody(messageReq: MessagesParamReq): JsonObject @@ -364,6 +366,12 @@ private class CampaignManagerImpl( dataStorage.saveAuthId(value) } + override var propertyId: Int + get() = dataStorage.propertyId + set(value) { + dataStorage.propertyId = value + } + // Optimized Implementation below val isNewUser: Boolean @@ -413,10 +421,11 @@ private class CampaignManagerImpl( val hasNonEligibleLocalDataVersion = dataStorage.localDataVersion != DataStorage.LOCAL_DATA_VERSION_HARDCODED_VALUE - val res = (isGdprOrCcpaUuidPresent && isLocalStateEmpty) || - isV6LocalStatePresent || - isV6LocalStatePresent2 || - hasNonEligibleLocalDataVersion + val isEligibleForCallingConsentStatus = + (isGdprOrCcpaUuidPresent && isLocalStateEmpty) || + isV6LocalStatePresent || + isV6LocalStatePresent2 || + hasNonEligibleLocalDataVersion logger?.computation( tag = "shouldCallConsentStatus", @@ -424,11 +433,11 @@ private class CampaignManagerImpl( isGdprOrCcpaUuidPresent[$isGdprOrCcpaUuidPresent] - isLocalStateEmpty[$isLocalStateEmpty] isV6LocalStatePresent[$isV6LocalStatePresent] - isV6LocalStatePresent2[$isV6LocalStatePresent2] hasNonEligibleLocalDataVersion[$hasNonEligibleLocalDataVersion] - res[$res] + isEligibleForCallingConsentStatus[$isEligibleForCallingConsentStatus] """.trimIndent() ) - return res + return isEligibleForCallingConsentStatus } override var gdprMessageMetaData: MessageMetaData? @@ -523,6 +532,27 @@ private class CampaignManagerImpl( override val hasLocalData: Boolean get() = dataStorage.gdprConsentStatus != null || dataStorage.ccpaConsentStatus != null + /** + * The method that checks if the authId or propertyId was changed, if so it will flush all the + * data. At the end, it will update the authId and propertyId with the corresponding values. + */ + override fun handleAuthIdOrPropertyIdChange( + newAuthId: String?, + newPropertyId: Int, + ) { + // flush local data if proper authId or propertyId change was detected + val isNewAuthId = newAuthId != null && newAuthId != authId + val isNewPropertyId = newPropertyId != propertyId + val hasPreviousPropertyId = propertyId != 0 + if (isNewAuthId || isNewPropertyId && hasPreviousPropertyId) { + dataStorage.clearAll() + } + + // update stored values of authId and propertyId + authId = newAuthId + propertyId = newPropertyId + } + override fun handleMetaDataResponse(response: MetaDataResp?) { // update meta data response in the data storage metaDataResp = response diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt index b8fc45cb7..45b3ce6cd 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/ServiceImpl.kt @@ -135,7 +135,6 @@ private class ServiceImpl( onFailure: (Throwable, Boolean) -> Unit, ) { execManager.executeOnWorkerThread { - campaignManager.authId = messageReq.authId if (connectionManager.isConnected.not()) { val noInternetConnectionException = NoInternetConnectionException() @@ -143,6 +142,12 @@ private class ServiceImpl( return@executeOnWorkerThread } + // check whether the authId or propertyId changed, and handle the flow accordingly + campaignManager.handleAuthIdOrPropertyIdChange( + newAuthId = messageReq.authId, + newPropertyId = spConfig.propertyId, + ) + val metadataResponse = this.getMetaData(messageReq.toMetaDataParamReq(campaigns4Config)) .executeOnLeft { metaDataError -> onFailure(metaDataError, true) diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorage.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorage.kt index 6a9339148..bd6d8c52f 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorage.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorage.kt @@ -17,6 +17,8 @@ internal interface DataStorage : DataStorageGdpr, DataStorageCcpa { const val CHOICE_RESP = "sp.key.choice" const val DATA_RECORDED_CONSENT = "sp.key.data.recorded.consent" + const val KEY_PROPERTY_ID = "sp.key.config.propertyId" + const val CONSENT_STATUS_RESPONSE = "sp.key.consent.status.response" const val GDPR_CONSENT_STATUS = "sp.gdpr.key.consent.status" const val CCPA_CONSENT_STATUS = "sp.ccpa.key.consent.status" @@ -41,6 +43,7 @@ internal interface DataStorage : DataStorageGdpr, DataStorageCcpa { var ccpaConsentStatus: String? var messagesOptimizedLocalState: String? var nonKeyedLocalState: String? + var propertyId: Int fun saveLocalState(value: String) fun getLocalState(): String? diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorageImpl.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorageImpl.kt index 16acfcca9..413cfa968 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorageImpl.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/data/local/DataStorageImpl.kt @@ -10,6 +10,7 @@ import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.CONSENT_STATU import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.CONSENT_STATUS_RESPONSE import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.DATA_RECORDED_CONSENT import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.GDPR_CONSENT_STATUS +import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.KEY_PROPERTY_ID import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_DATA_VERSION_HARDCODED_VALUE import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_DATA_VERSION_KEY import com.sourcepoint.cmplibrary.data.local.DataStorage.Companion.LOCAL_STATE @@ -138,6 +139,12 @@ private class DataStorageImpl( .putString(NON_KEYED_LOCAL_STATE, value) .apply() } + override var propertyId: Int + get() = preference.getInt(KEY_PROPERTY_ID, 0) + set(value) = preference + .edit() + .putInt(KEY_PROPERTY_ID, value) + .apply() override var consentStatus: String? get() = preference.getString(CONSENT_STATUS, null) @@ -210,6 +217,7 @@ private class DataStorageImpl( .remove(CCPA_CONSENT_STATUS) .remove(MESSAGES_OPTIMIZED_LOCAL_STATE) .remove(NON_KEYED_LOCAL_STATE) + .remove(KEY_PROPERTY_ID) .apply() } diff --git a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinOldConsentTest.kt b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinOldConsentTest.kt index 5cca5b064..449df9826 100644 --- a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinOldConsentTest.kt +++ b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinOldConsentTest.kt @@ -145,7 +145,7 @@ class MainActivityKotlinOldConsentTest { @Test fun GIVEN_an_old_CCPA_GDPR_v6LocalState_VERIFY_that_the_migration_is_performed() = runBlocking { - val v6LocalState = JSONObject(TestData.storedConsentGdprCcap) + val v6LocalState = JSONObject(TestData.storedConsentGdprCcpa) val spClient = mockk(relaxed = true) @@ -222,7 +222,7 @@ class MainActivityKotlinOldConsentTest { @Test fun GIVEN_an_old_CCPAv6LocalState_VERIFY_that_the_migration_is_performed() = runBlocking { - val v6LocalState = JSONObject(TestData.storedConsentCcap) + val v6LocalState = JSONObject(TestData.storedConsentCcpa) val spClient = mockk(relaxed = true) diff --git a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinTest.kt b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinTest.kt index ea251c26c..a8e279f5f 100644 --- a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinTest.kt +++ b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/MainActivityKotlinTest.kt @@ -28,9 +28,7 @@ import com.sourcepoint.app.v6.TestUseCase.Companion.clickOnRefreshBtnActivity import com.sourcepoint.app.v6.TestUseCase.Companion.mockModule import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptAllOnWebView import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptCcpaOnWebView -import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnOk import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnWebView -import com.sourcepoint.app.v6.TestUseCase.Companion.tapAcceptOnWebViewDE import com.sourcepoint.app.v6.TestUseCase.Companion.tapCancelOnWebView import com.sourcepoint.app.v6.TestUseCase.Companion.tapFeaturesOnWebView import com.sourcepoint.app.v6.TestUseCase.Companion.tapNetworkOnWebView @@ -59,6 +57,7 @@ import org.junit.After import org.junit.Test import org.junit.runner.RunWith import org.koin.core.context.loadKoinModules +import java.util.UUID @RunWith(AndroidJUnit4ClassRunner::class) class MainActivityKotlinTest { @@ -1076,6 +1075,86 @@ class MainActivityKotlinTest { } } + /** + * UI test that verifies that there was a clean up of local data after the user changed their + * auth ID. Due to the fact that the clean up happens, the message flow appears again, the user + * make their choice and the consent UUIDs of both campaigns changes. + */ + @Test + fun given_the_user_has_consent_and_the_auth_id_changes_then_should_flush_data() = runBlocking { + + val storedConsent = JSONObject(TestData.storedConsentWithAuthIdAndPropertyIdV741) + val spClient = mockk(relaxed = true) + val newAuthId = UUID.randomUUID().toString() + + loadKoinModules( + mockModule( + spConfig = spConf, + gdprPmId = "488393", + ccpaPmId = "509688", + spClientObserver = listOf(spClient), + diagnostic = storedConsent.toList(), + pAuthId = newAuthId + ) + ) + + scenario = launchActivity() + + wr { tapAcceptAllOnWebView() } + wr { tapAcceptAllOnWebView() } + + wr { verify(exactly = 0) { spClient.onError(any()) } } + wr { verify(exactly = 2) { spClient.onUIReady(any()) } } + wr { verify(exactly = 1) { spClient.onSpFinished(any()) } } + + scenario.onActivity { activity -> + PreferenceManager.getDefaultSharedPreferences(activity).run { + getString("sp.gdpr.authId", null).assertEquals(newAuthId) + } + } + } + + /** + * UI test that verifies that there was a clean up of local data after the user changed their + * property ID. Due to the fact that the clean up happens, the message flow appears again, the user + * make their choice and the consent UUIDs of both campaigns changes. + */ + @Test + fun given_the_user_has_consent_and_the_property_id_changes_then_should_flush_data() = runBlocking { + + val storedConsent = JSONObject(TestData.storedConsentWithAuthIdAndPropertyIdV741) + val spClient = mockk(relaxed = true) + val storedPropertyId = 31226 + val newPropertyId = 16893 + + loadKoinModules( + mockModule( + spConfig = spConf, + gdprPmId = "488393", + ccpaPmId = "509688", + spClientObserver = listOf(spClient), + diagnostic = storedConsent.toList() + listOf( + Pair("sp.key.config.propertyId", storedPropertyId) + ), + ) + ) + + scenario = launchActivity() + + wr { tapAcceptAllOnWebView() } + wr { tapAcceptAllOnWebView() } + + wr { verify(exactly = 0) { spClient.onError(any()) } } + wr { verify(exactly = 2) { spClient.onUIReady(any()) } } + wr { verify(exactly = 1) { spClient.onSpFinished(any()) } } + + scenario.onActivity { activity -> + PreferenceManager.getDefaultSharedPreferences(activity).run { + getInt("sp.key.config.propertyId", 0).assertEquals(newPropertyId) + } + } + } + private fun check(block: () -> E): E? { return try { block.invoke() diff --git a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/TestData.kt b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/TestData.kt index b3d1675ef..3dc3355fa 100644 --- a/samples/app/src/androidTest/java/com/sourcepoint/app/v6/TestData.kt +++ b/samples/app/src/androidTest/java/com/sourcepoint/app/v6/TestData.kt @@ -71,7 +71,7 @@ object TestData { var FEATURES = "Features" var PURPOSES = "Purposes" - val storedConsentGdprCcap = """ + val storedConsentGdprCcpa = """ { "sp.gdpr.key.date.created": "2022-12-07T15:00:48.255Z", "IABTCF_PurposeOneTreatment": 0, @@ -119,7 +119,7 @@ object TestData { } """.trimIndent() - val storedConsentCcap = """ + val storedConsentCcpa = """ { "sp.ccpa.key": "{\"applies\":true,\"message\":{\"message_choice\":[{\"button_text\":\"Dismiss\",\"choice_id\":5681956,\"type\":15},{\"button_text\":\"1623758277257\",\"choice_id\":5681957,\"iframe_url\":\"https:\\/\\/ccpa-notice.sp-prod.net\\/ccpa_pm\\/index.html?message_id=509688\",\"type\":12},{\"button_text\":\"1623758165801\",\"choice_id\":5681958,\"type\":13},{\"button_text\":\"1623758176582\",\"choice_id\":5681959,\"type\":11}],\"message_json\":{\"message_json_string\":\"{\\\"type\\\":\\\"Notice\\\",\\\"name\\\":\\\"CCPA Message\\\",\\\"settings\\\":{},\\\"children\\\":[{\\\"type\\\":\\\"Text\\\",\\\"name\\\":\\\"Text\\\",\\\"settings\\\":{\\\"languages\\\":{\\\"EN\\\":{\\\"text\\\":\\\"

CCPA Message<\\/p>\\\"}},\\\"text\\\":\\\"

CCPA Message<\\/p>\\\"},\\\"children\\\":[]},{\\\"type\\\":\\\"Button\\\",\\\"name\\\":\\\"Button\\\",\\\"settings\\\":{\\\"languages\\\":{\\\"EN\\\":{\\\"text\\\":\\\"Show Options\\\"}},\\\"text\\\":\\\"Show Options\\\",\\\"choice_option\\\":{\\\"type\\\":12,\\\"data\\\":{\\\"button_text\\\":\\\"1623758277257\\\",\\\"privacy_manager_iframe_url\\\":\\\"https:\\/\\/ccpa-notice.sp-prod.net\\/ccpa_pm\\/index.html?message_id=509688\\\",\\\"consent_origin\\\":\\\"https:\\/\\/ccpa-service.sp-prod.net\\\"}}},\\\"children\\\":[]},{\\\"type\\\":\\\"Button\\\",\\\"name\\\":\\\"Button\\\",\\\"settings\\\":{\\\"languages\\\":{\\\"EN\\\":{\\\"text\\\":\\\"Reject All\\\"}},\\\"text\\\":\\\"Reject All\\\",\\\"choice_option\\\":{\\\"type\\\":13,\\\"data\\\":{\\\"button_text\\\":\\\"1623758165801\\\",\\\"consent_origin\\\":\\\"https:\\/\\/ccpa-service.sp-prod.net\\\",\\\"consent_language\\\":\\\"EN\\\"}},\\\"background\\\":\\\"#9a244f\\\"},\\\"children\\\":[]},{\\\"type\\\":\\\"Button\\\",\\\"name\\\":\\\"Button\\\",\\\"settings\\\":{\\\"languages\\\":{\\\"EN\\\":{\\\"text\\\":\\\"Accept All\\\"}},\\\"text\\\":\\\"Accept All\\\",\\\"choice_option\\\":{\\\"type\\\":11,\\\"data\\\":{\\\"button_text\\\":\\\"1623758176582\\\",\\\"consent_origin\\\":\\\"https:\\/\\/ccpa-service.sp-prod.net\\\",\\\"consent_language\\\":\\\"EN\\\"}},\\\"background\\\":\\\"#4f7a28\\\"},\\\"children\\\":[]}],\\\"compliance_status\\\":false,\\\"compliance_list\\\":[]}\",\"name\":\"CCPA Message\",\"settings\":{},\"signature\":[180,139,208,159,150,52,33,251,87,207,64,248,255,84,201,7,141,197,107,32,181,3,205,144,199,255,101,82,87,35,123,41,52,2,44,110,7,114,9,78,242,57,177,23,70,241,39,206,92,37,120,165,67,42,243,33,96,114,75,181,13,206,191,7],\"type\":\"Notice\"},\"site_id\":16893},\"messageMetaData\":{\"bucket\":469,\"categoryId\":2,\"messageId\":616558,\"msgDescription\":\"\",\"prtnUUID\":\"5cfc830e-3d3a-4b18-979d-c543dd065516\",\"subCategoryId\":1},\"type\":\"CCPA\",\"url\":\"https:\\/\\/cdn.privacy-mgmt.com\\/index.html?ccpaUUID=41590576-163b-4acf-851e-820e41f415fa&message_id=616558&consentLanguage=EN&preload_message=true&version=v1\",\"userConsent\":{\"dateCreated\":\"2022-12-08T11:30:43.790Z\",\"newUser\":true,\"rejectedAll\":false,\"rejectedCategories\":[],\"rejectedVendors\":[],\"signedLspa\":false,\"status\":\"rejectedNone\",\"uspstring\":\"1YNN\"}}", "IABUSPrivacy_String": "1YNN", @@ -246,6 +246,50 @@ object TestData { } """.trimIndent() + val storedConsentWithAuthIdAndPropertyIdV741 = """ + { + "sp.gdpr.authId": "ee7ea3b8-9609-4ba4-be07-0986d32cdd1e", + "sp.key.config.propertyId": 16893, + "sp.ccpa.key.consent.status": "{\n \"applies\": true,\n \"consentedAll\": true,\n \"dateCreated\": \"2023-10-20T12:49:57.066Z\",\n \"rejectedAll\": false,\n \"rejectedCategories\": [\n ],\n \"rejectedVendors\": [\n ],\n \"signedLspa\": false,\n \"status\": \"consentedAll\",\n \"uuid\": \"4c99bd2b-b40b-4aef-b762-20397e07d026\",\n \"webConsentPayload\": {\n \"actions\": [\n ],\n \"cookies\": [\n {\n \"key\": \"ccpaConsentAll\",\n \"value\": true,\n \"setPath\": true,\n \"maxAge\": 31536000\n },\n {\n \"key\": \"ccpaReject\",\n \"value\": false,\n \"setPath\": true,\n \"maxAge\": 31536000\n },\n {\n \"key\": \"consentStatus\",\n \"value\": \"consentedAll\",\n \"setPath\": true,\n \"maxAge\": 31536000\n }\n ],\n \"consentedAll\": true,\n \"dateCreated\": \"2023-10-20T12:48:43.914Z\",\n \"expirationDate\": \"2024-10-19T12:48:43.914Z\",\n \"rejectedAll\": false,\n \"rejectedCategories\": [\n ],\n \"rejectedVendors\": [\n ],\n \"signedLspa\": false,\n \"status\": \"consentedAll\"\n }\n}", + "IABTCF_PurposeOneTreatment": 0, + "sp.ccpa.consentUUID": "4c99bd2b-b40b-4aef-b762-20397e07d026", + "sp.ccpa.key.message.metadata": "{\n \"bucket\": 365,\n \"categoryId\": 2,\n \"messageId\": 766174,\n \"msgDescription\": \"\",\n \"prtnUUID\": \"0f7a409a-23de-4598-a39a-148cc3aa7325\",\n \"subCategoryId\": 5\n}", + "IABTCF_PublisherConsent": "0000000000", + "IABTCF_gdprApplies": 1, + "IABTCF_PublisherRestrictions4": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "IABTCF_PublisherRestrictions2": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "sp.key.messages.v7.local.state": "{\n \"gdpr\": {\n \"mmsCookies\": [\n \"_sp_v1_ss=1:H4sIAAAAAAAAAItWqo5RKimOUbKKBjLyQAyD2lidGKVUEDOvNCcHyC4BK6iurVWKBQAW54XRMAAAAA%3D%3D\"\n ],\n \"propertyId\": 16893,\n \"messageId\": 825386\n },\n \"ccpa\": {\n \"mmsCookies\": [\n \"_sp_v1_ss=1:H4sIAAAAAAAAAItWqo5RKimOUbKKBjLyQAyD2lidGKVUEDOvNCcHyC4BK6iurVWKBQAW54XRMAAAAA%3D%3D\"\n ],\n \"propertyId\": 16893,\n \"messageId\": 766174\n }\n}", + "IABTCF_PublisherRestrictions7": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "IABTCF_VendorLegitimateInterests": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "IABTCF_PublisherCustomPurposesConsents": "0000000000", + "IABTCF_PolicyVersion": 4, + "IABTCF_AddtlConsent": "1~899", + "IABTCF_PurposeLegitimateInterests": "0100000000", + "IABTCF_CmpSdkID": 6, + "IABTCF_CmpSdkVersion": 2, + "IABTCF_PublisherCustomPurposesLegitimateInterests": "0000000000", + "sp.key.meta.data": "{\n \"ccpa\": {\n \"applies\": true,\n \"sampleRate\": 1.0\n },\n \"gdpr\": {\n \"additionsChangeDate\": \"2023-09-19T13:53:18.421Z\",\n \"applies\": true,\n \"getMessageAlways\": false,\n \"_id\": \"608badf1a22863112f750a18\",\n \"legalBasisChangeDate\": \"2021-06-30T15:52:45.117Z\",\n \"version\": 44,\n \"sampleRate\": 1.0\n }\n}", + "sp.gdpr.key.sampling.result": true, + "IABUSPrivacy_String": "1YNN", + "sp.ccpa.key.sampling.result": true, + "IABTCF_VendorConsents": "000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "IABTCF_PublisherCC": "DE", + "IABTCF_SpecialFeaturesOptIns": "11", + "client_pref_key": "client_pref_val", + "IABTCF_PublisherLegitimateInterests": "0000000000", + "IABTCF_PublisherRestrictions10": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "sp.gdpr.key.applies": true, + "IABTCF_TCString": "CPz8Z4APz8Z4AAGABCENAWEsAOCAAEAAAAYgASAAAAAAQAAACBAAIAJBAAEAEg4ACACQoABABIAA.YAAAAAAAAAAA", + "IABTCF_UseNonStandardTexts": 0, + "sp.gdpr.consentUUID": "14121a31-1531-44a0-85af-bf47a3a12c1b_24", + "sp.key.localDataVersion": 1, + "sp.gdpr.key.message.metadata": "{\n \"bucket\": 159,\n \"categoryId\": 1,\n \"messageId\": 825386,\n \"msgDescription\": \"\",\n \"prtnUUID\": \"03d4d5be-f4cb-44c3-ae80-7dc6462d11b7\",\n \"subCategoryId\": 5\n}", + "IABTCF_PurposeConsents": "1110000010", + "sp.gdpr.key.consent.status": "{\n \"applies\": true,\n \"gdprApplies\": true,\n \"categories\": [\n \"608bad95d08d3112188e0e29\",\n \"608bad95d08d3112188e0e2f\",\n \"608bad95d08d3112188e0e36\",\n \"608bad96d08d3112188e0e59\",\n \"60b65857619abe242bed971e\"\n ],\n \"consentAllRef\": \"65321b6c4f9aee6af73288d6\",\n \"consentedToAll\": true,\n \"legIntCategories\": [\n \"608bad95d08d3112188e0e2f\"\n ],\n \"legIntVendors\": [\n \"5f1b2fbeb8e05c306f2a1eb9\"\n ],\n \"postPayload\": {\n \"consentAllRef\": \"65321b6c4f9aee6af73288d6\",\n \"granularStatus\": {\n \"defaultConsent\": false,\n \"previousOptInAll\": false,\n \"purposeConsent\": \"ALL\",\n \"purposeLegInt\": \"ALL\",\n \"vendorConsent\": \"ALL\",\n \"vendorLegInt\": \"ALL\"\n },\n \"vendorListId\": \"608badf1a22863112f750a18\"\n },\n \"rejectedAny\": false,\n \"specialFeatures\": [\n \"5e37fc3e973acf1e955b8966\",\n \"5e37fc3e973acf1e955b8967\"\n ],\n \"vendors\": [\n \"5f1b2fbeb8e05c306f2a1eb9\",\n \"5ff4d000a228633ac048be41\",\n \"5e7ced57b8e05c485246cce0\"\n ],\n \"addtlConsent\": \"1~899\",\n \"consentStatus\": {\n \"consentedAll\": true,\n \"consentedToAny\": true,\n \"granularStatus\": {\n \"defaultConsent\": false,\n \"previousOptInAll\": false,\n \"purposeConsent\": \"ALL\",\n \"purposeLegInt\": \"ALL\",\n \"vendorConsent\": \"ALL\",\n \"vendorLegInt\": \"ALL\"\n },\n \"hasConsentData\": true,\n \"rejectedAny\": false,\n \"rejectedLI\": false\n },\n \"customVendorsResponse\": {\n \"consentedPurposes\": [\n {\n \"_id\": \"608bad95d08d3112188e0e29\",\n \"name\": \"Store and\\/or access information on a device\"\n },\n {\n \"_id\": \"608bad95d08d3112188e0e2f\",\n \"name\": \"Use limited data to select advertising\"\n },\n {\n \"_id\": \"608bad95d08d3112188e0e36\",\n \"name\": \"Create profiles for personalised advertising\"\n },\n {\n \"_id\": \"608bad96d08d3112188e0e59\",\n \"name\": \"Understand audiences through statistics or combinations of data from different sources\"\n },\n {\n \"_id\": \"60b65857619abe242bed971e\",\n \"name\": \"Our Custom Purpose\"\n }\n ],\n \"consentedVendors\": [\n {\n \"_id\": \"5ff4d000a228633ac048be41\",\n \"name\": \"Game Accounts\",\n \"vendorType\": \"CUSTOM\"\n },\n {\n \"_id\": \"5f1b2fbeb8e05c306f2a1eb9\",\n \"name\": \"QuarticON\",\n \"vendorType\": \"CUSTOM\"\n }\n ],\n \"legIntPurposes\": [\n {\n \"_id\": \"608bad95d08d3112188e0e2f\",\n \"name\": \"Use limited data to select advertising\"\n }\n ]\n },\n \"dateCreated\": \"2023-10-20T12:48:42.746Z\",\n \"euconsent\": \"CPz8Z4APz8Z4AAGABCENAWEsAOCAAEAAAAYgASAAAAAAQAAACBAAIAJBAAEAEg4ACACQoABABIAA.YAAAAAAAAAAA\",\n \"grants\": {\n \"5e7ced57b8e05c485246cce0\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e29\": true,\n \"608bad95d08d3112188e0e36\": true,\n \"608bad96d08d3112188e0e59\": true,\n \"60b65857619abe242bed971e\": true\n }\n },\n \"5f1b2fbeb8e05c306f2a1eb9\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e29\": true,\n \"608bad95d08d3112188e0e2f\": true\n }\n },\n \"5ff4d000a228633ac048be41\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e2f\": true,\n \"608bad95d08d3112188e0e36\": true\n }\n }\n },\n \"TCData\": {\n \"IABTCF_AddtlConsent\": \"1~899\",\n \"IABTCF_CmpSdkID\": 6,\n \"IABTCF_CmpSdkVersion\": 2,\n \"IABTCF_PolicyVersion\": 4,\n \"IABTCF_PublisherCC\": \"DE\",\n \"IABTCF_PurposeOneTreatment\": 0,\n \"IABTCF_UseNonStandardTexts\": 0,\n \"IABTCF_TCString\": \"CPz8Z4APz8Z4AAGABCENAWEsAOCAAEAAAAYgASAAAAAAQAAACBAAIAJBAAEAEg4ACACQoABABIAA.YAAAAAAAAAAA\",\n \"IABTCF_VendorConsents\": \"000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"IABTCF_VendorLegitimateInterests\": \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"IABTCF_PurposeConsents\": \"1110000010\",\n \"IABTCF_PurposeLegitimateInterests\": \"0100000000\",\n \"IABTCF_SpecialFeaturesOptIns\": \"11\",\n \"IABTCF_PublisherConsent\": \"0000000000\",\n \"IABTCF_PublisherLegitimateInterests\": \"0000000000\",\n \"IABTCF_PublisherCustomPurposesConsents\": \"0000000000\",\n \"IABTCF_PublisherCustomPurposesLegitimateInterests\": \"0000000000\",\n \"IABTCF_gdprApplies\": 1,\n \"IABTCF_PublisherRestrictions2\": \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"IABTCF_PublisherRestrictions4\": \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"IABTCF_PublisherRestrictions7\": \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"IABTCF_PublisherRestrictions10\": \"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n },\n \"vendorListId\": \"608badf1a22863112f750a18\",\n \"webConsentPayload\": {\n \"actions\": [\n ],\n \"addtlConsent\": \"1~899\",\n \"cookies\": [\n ],\n \"consentStatus\": {\n \"rejectedAny\": false,\n \"rejectedLI\": false,\n \"consentedAll\": true,\n \"granularStatus\": {\n \"vendorConsent\": \"ALL\",\n \"vendorLegInt\": \"ALL\",\n \"purposeConsent\": \"ALL\",\n \"purposeLegInt\": \"ALL\",\n \"previousOptInAll\": false,\n \"defaultConsent\": false\n },\n \"hasConsentData\": true,\n \"consentedToAny\": true\n },\n \"customVendorsResponse\": {\n \"consentedVendors\": [\n {\n \"_id\": \"5ff4d000a228633ac048be41\",\n \"name\": \"Game Accounts\",\n \"vendorType\": \"CUSTOM\"\n },\n {\n \"_id\": \"5f1b2fbeb8e05c306f2a1eb9\",\n \"name\": \"QuarticON\",\n \"vendorType\": \"CUSTOM\"\n }\n ],\n \"consentedPurposes\": [\n {\n \"_id\": \"608bad95d08d3112188e0e29\",\n \"name\": \"Store and\\/or access information on a device\"\n },\n {\n \"_id\": \"608bad95d08d3112188e0e2f\",\n \"name\": \"Use limited data to select advertising\"\n },\n {\n \"_id\": \"608bad95d08d3112188e0e36\",\n \"name\": \"Create profiles for personalised advertising\"\n },\n {\n \"_id\": \"608bad96d08d3112188e0e59\",\n \"name\": \"Understand audiences through statistics or combinations of data from different sources\"\n },\n {\n \"_id\": \"60b65857619abe242bed971e\",\n \"name\": \"Our Custom Purpose\"\n }\n ],\n \"legIntPurposes\": [\n {\n \"_id\": \"608bad95d08d3112188e0e2f\",\n \"name\": \"Use limited data to select advertising\"\n }\n ]\n },\n \"dateCreated\": \"2023-10-20T12:48:42.746Z\",\n \"expirationDate\": \"2024-10-19T12:48:42.746Z\",\n \"euconsent\": \"CPz8Z4APz8Z4AAGABCENAWEsAOCAAEAAAAYgASAAAAAAQAAACBAAIAJBAAEAEg4ACACQoABABIAA.YAAAAAAAAAAA\",\n \"gdprApplies\": true,\n \"grants\": {\n \"5e7ced57b8e05c485246cce0\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e29\": true,\n \"608bad95d08d3112188e0e36\": true,\n \"608bad96d08d3112188e0e59\": true,\n \"60b65857619abe242bed971e\": true\n }\n },\n \"5f1b2fbeb8e05c306f2a1eb9\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e29\": true,\n \"608bad95d08d3112188e0e2f\": true\n }\n },\n \"5ff4d000a228633ac048be41\": {\n \"vendorGrant\": true,\n \"purposeGrants\": {\n \"608bad95d08d3112188e0e2f\": true,\n \"608bad95d08d3112188e0e36\": true\n }\n }\n },\n \"vendorListId\": \"608badf1a22863112f750a18\"\n }\n}", + "sp.key.messages.v7.nonKeyedLocalState": "{\n \"ccpa\": {\n \"_sp_v1_data\": \"585620\",\n \"_sp_v1_p\": \"365\"\n },\n \"gdpr\": {\n \"_sp_v1_data\": \"633830\",\n \"_sp_v1_p\": \"159\"\n }\n}" + } + """.trimIndent() + val storedConsentGDPR_V7 = """ { "IABTCF_PurposeOneTreatment": 0,