Skip to content

Commit b12c5f2

Browse files
authored
Merge pull request #17280 from wordpress-mobile/issue/17218-blogging-reminders-provider
[Blogging Reminders Sync] Implement blogging reminders provider
2 parents 6dce4e3 + fa45c9c commit b12c5f2

7 files changed

Lines changed: 182 additions & 18 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.wordpress.android.bloggingreminders.provider
2+
3+
import android.database.Cursor
4+
import android.net.Uri
5+
import kotlinx.coroutines.flow.first
6+
import kotlinx.coroutines.runBlocking
7+
import org.wordpress.android.WordPress
8+
import org.wordpress.android.fluxc.model.BloggingRemindersModel
9+
import org.wordpress.android.fluxc.model.SiteModel
10+
import org.wordpress.android.fluxc.store.BloggingRemindersStore
11+
import org.wordpress.android.fluxc.store.SiteStore
12+
import org.wordpress.android.provider.query.QueryContentProvider
13+
import org.wordpress.android.provider.query.QueryResult
14+
import org.wordpress.android.util.publicdata.ClientVerification
15+
import org.wordpress.android.util.signature.SignatureNotFoundException
16+
import javax.inject.Inject
17+
18+
typealias SiteModelBloggingReminderMap = Map<SiteModel, BloggingRemindersModel>
19+
20+
class BloggingRemindersProvider : QueryContentProvider() {
21+
@Inject lateinit var bloggingRemindersStore: BloggingRemindersStore
22+
@Inject lateinit var siteStore: SiteStore
23+
@Inject lateinit var queryResult: QueryResult
24+
@Inject lateinit var clientVerification: ClientVerification
25+
26+
override fun onCreate(): Boolean {
27+
return true
28+
}
29+
30+
@Suppress("SwallowedException")
31+
override fun query(
32+
uri: Uri,
33+
projection: Array<out String>?,
34+
selection: String?,
35+
selectionArgs: Array<out String>?,
36+
sortOrder: String?
37+
): Cursor? {
38+
inject()
39+
return context?.let {
40+
try {
41+
if (clientVerification.canTrust(callingPackage)) {
42+
runBlocking {
43+
val allSiteModels = siteStore.sites
44+
val filteredBloggingReminders = allSiteModels.map { siteModel ->
45+
bloggingRemindersStore.bloggingRemindersModel(siteModel.id).first()
46+
}.filter { bloggingRemindersModel ->
47+
bloggingRemindersModel.enabledDays.isNotEmpty()
48+
}
49+
val filteredSiteIds = filteredBloggingReminders.map { bloggingReminder ->
50+
bloggingReminder.siteId
51+
}
52+
val filteredSiteModels = allSiteModels.filter { siteModel ->
53+
filteredSiteIds.contains(siteModel.id)
54+
}
55+
val result: SiteModelBloggingReminderMap =
56+
filteredSiteModels.zip(filteredBloggingReminders).toMap()
57+
queryResult.createCursor(result)
58+
}
59+
} else null
60+
} catch (signatureNotFoundException: SignatureNotFoundException) {
61+
null
62+
}
63+
}
64+
}
65+
66+
private fun inject() {
67+
if (!this::bloggingRemindersStore.isInitialized) {
68+
(context?.applicationContext as WordPress).component().inject(this)
69+
}
70+
}
71+
}

WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.automattic.android.tracks.crashlogging.CrashLogging;
44

5+
import org.wordpress.android.bloggingreminders.provider.BloggingRemindersProvider;
56
import org.wordpress.android.push.GCMMessageService;
67
import org.wordpress.android.push.GCMRegistrationIntentService;
78
import org.wordpress.android.push.NotificationsProcessingService;
@@ -652,4 +653,6 @@ public interface AppComponent {
652653
void inject(WeekWidgetBlockListProviderFactory object);
653654

654655
void inject(UserFlagsProvider object);
656+
657+
void inject(BloggingRemindersProvider object);
655658
}

WordPress/src/main/java/org/wordpress/android/sharedlogin/provider/SharedLoginProvider.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ import org.wordpress.android.WordPress
66
import org.wordpress.android.fluxc.store.AccountStore
77
import org.wordpress.android.provider.query.QueryContentProvider
88
import org.wordpress.android.provider.query.QueryResult
9-
import org.wordpress.android.util.publicdata.JetpackPublicData
9+
import org.wordpress.android.util.publicdata.ClientVerification
1010
import org.wordpress.android.util.signature.SignatureNotFoundException
11-
import org.wordpress.android.util.signature.SignatureUtils
1211
import javax.inject.Inject
1312

1413
class SharedLoginProvider : QueryContentProvider() {
1514
@Inject lateinit var accountStore: AccountStore
16-
@Inject lateinit var signatureUtils: SignatureUtils
1715
@Inject lateinit var queryResult: QueryResult
18-
@Inject lateinit var jetpackPublicData: JetpackPublicData
16+
@Inject lateinit var clientVerification: ClientVerification
1917

2018
override fun onCreate(): Boolean {
2119
return true
@@ -32,11 +30,7 @@ class SharedLoginProvider : QueryContentProvider() {
3230
inject()
3331
return context?.let {
3432
try {
35-
val callerPackageId = callingPackage
36-
val callerExpectedPackageId = jetpackPublicData.currentPackageId()
37-
val callerSignatureHash = signatureUtils.getSignatureHash(it, callerExpectedPackageId)
38-
val callerExpectedSignatureHash = jetpackPublicData.currentPublicKeyHash()
39-
if (callerPackageId == callerExpectedPackageId && callerSignatureHash == callerExpectedSignatureHash) {
33+
if (clientVerification.canTrust(callingPackage)) {
4034
queryResult.createCursor(accountStore.accessToken)
4135
} else null
4236
} catch (signatureNotFoundException: SignatureNotFoundException) {

WordPress/src/main/java/org/wordpress/android/userflags/provider/UserFlagsProvider.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ import org.wordpress.android.provider.query.QueryResult
99
import org.wordpress.android.ui.prefs.AppPrefs.DeletablePrefKey
1010
import org.wordpress.android.ui.prefs.AppPrefs.UndeletablePrefKey
1111
import org.wordpress.android.ui.prefs.AppPrefsWrapper
12-
import org.wordpress.android.util.publicdata.JetpackPublicData
12+
import org.wordpress.android.util.publicdata.ClientVerification
1313
import org.wordpress.android.util.signature.SignatureNotFoundException
14-
import org.wordpress.android.util.signature.SignatureUtils
1514
import javax.inject.Inject
1615

1716
class UserFlagsProvider : QueryContentProvider() {
1817
@Inject lateinit var appPrefsWrapper: AppPrefsWrapper
1918
@Inject lateinit var siteStore: SiteStore
20-
@Inject lateinit var signatureUtils: SignatureUtils
2119
@Inject lateinit var queryResult: QueryResult
22-
@Inject lateinit var jetpackPublicData: JetpackPublicData
20+
@Inject lateinit var clientVerification: ClientVerification
2321

2422
private val userFlagsKeysSet: Set<String> = setOf(
2523
DeletablePrefKey.MAIN_PAGE_INDEX.name,
@@ -70,11 +68,7 @@ class UserFlagsProvider : QueryContentProvider() {
7068
inject()
7169
return context?.let {
7270
try {
73-
val callerPackageId = callingPackage
74-
val callerExpectedPackageId = jetpackPublicData.currentPackageId()
75-
val callerSignatureHash = signatureUtils.getSignatureHash(it, callerExpectedPackageId)
76-
val callerExpectedSignatureHash = jetpackPublicData.currentPublicKeyHash()
77-
if (callerPackageId == callerExpectedPackageId && callerSignatureHash == callerExpectedSignatureHash) {
71+
if (clientVerification.canTrust(callingPackage)) {
7872
val userFlagsMap = appPrefsWrapper.getAllPrefs()
7973
.filter { entry ->
8074
userFlagsKeysSet.contains(entry.key)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.wordpress.android.util.publicdata
2+
3+
import org.wordpress.android.util.signature.SignatureUtils
4+
import org.wordpress.android.viewmodel.ContextProvider
5+
import javax.inject.Inject
6+
7+
class ClientVerification @Inject constructor(
8+
private val jetpackPublicData: JetpackPublicData,
9+
private val signatureUtils: SignatureUtils,
10+
private val contextProvider: ContextProvider,
11+
) {
12+
fun canTrust(callerPackage: String?): Boolean {
13+
if (callerPackage == null) {
14+
return false
15+
}
16+
val callerExpectedPackageId = jetpackPublicData.currentPackageId()
17+
val callerSignatureHash = signatureUtils.getSignatureHash(contextProvider.getContext(), callerExpectedPackageId)
18+
val callerExpectedSignatureHash = jetpackPublicData.currentPublicKeyHash()
19+
return callerPackage == callerExpectedPackageId && callerSignatureHash == callerExpectedSignatureHash
20+
}
21+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.wordpress.android.util.publicdata
2+
3+
import com.nhaarman.mockitokotlin2.mock
4+
import com.nhaarman.mockitokotlin2.verify
5+
import com.nhaarman.mockitokotlin2.whenever
6+
import org.junit.Assert
7+
import org.junit.Before
8+
import org.junit.Test
9+
import org.wordpress.android.util.signature.SignatureUtils
10+
import org.wordpress.android.viewmodel.ContextProvider
11+
12+
class ClientVerificationTest {
13+
private val jetpackPublicData: JetpackPublicData = mock()
14+
private val signatureUtils: SignatureUtils = mock()
15+
private val contextProvider: ContextProvider = mock()
16+
private val classToTest = ClientVerification(jetpackPublicData, signatureUtils, contextProvider)
17+
18+
private val expectedPackage = "match"
19+
private val expectedSignatureHash = "signatureHash"
20+
21+
@Before
22+
fun setup() {
23+
whenever(jetpackPublicData.currentPackageId()).thenReturn(expectedPackage)
24+
whenever(jetpackPublicData.currentPublicKeyHash()).thenReturn(expectedSignatureHash)
25+
whenever(signatureUtils.getSignatureHash(contextProvider.getContext(), expectedPackage))
26+
.thenReturn(expectedSignatureHash)
27+
}
28+
29+
@Test
30+
fun `Should return false if calling package is null when canTrust is called`() {
31+
val expected = false
32+
val actual = classToTest.canTrust(null)
33+
Assert.assertEquals(expected, actual)
34+
}
35+
36+
@Test
37+
fun `Should return false if caller package does not match the expected when canTrust is called`() {
38+
val expected = false
39+
val actual = classToTest.canTrust("no_match")
40+
Assert.assertEquals(expected, actual)
41+
}
42+
43+
@Test
44+
fun `Should return false if caller signature hash does not match the expected when canTrust is called`() {
45+
whenever(signatureUtils.getSignatureHash(contextProvider.getContext(), expectedPackage))
46+
.thenReturn("no_match")
47+
val expected = false
48+
val actual = classToTest.canTrust(expectedPackage)
49+
Assert.assertEquals(expected, actual)
50+
}
51+
52+
@Test
53+
fun `Should return true if caller package and signature hash match the expected when canTrust is called`() {
54+
val expected = true
55+
val actual = classToTest.canTrust(expectedPackage)
56+
Assert.assertEquals(expected, actual)
57+
}
58+
59+
@Test
60+
fun `Should call jetpackPublicData currentPackageId when canTrust is called`() {
61+
classToTest.canTrust(expectedPackage)
62+
verify(jetpackPublicData).currentPackageId()
63+
}
64+
65+
@Test
66+
fun `Should call signatureUtils getSignatureHash when canTrust is called`() {
67+
classToTest.canTrust(expectedPackage)
68+
verify(signatureUtils).getSignatureHash(contextProvider.getContext(), expectedPackage)
69+
}
70+
71+
@Test
72+
fun `Should call jetpackPublicData currentPublicKeyHash when canTrust is called`() {
73+
classToTest.canTrust(expectedPackage)
74+
verify(jetpackPublicData).currentPublicKeyHash()
75+
}
76+
}

WordPress/src/wordpress/AndroidManifest.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@
1111
android:name=".userflags.provider.UserFlagsProvider"
1212
android:authorities="${applicationId}.UserFlagsProvider"
1313
android:exported="true" />
14+
15+
<provider
16+
android:name=".bloggingreminders.provider.BloggingRemindersProvider"
17+
android:authorities="${applicationId}.BloggingRemindersProvider"
18+
android:exported="true" />
1419
</application>
1520
</manifest>

0 commit comments

Comments
 (0)