Check if in-app update allowed

remotes/weblate/legacy v0.3
Koitharu 6 years ago
parent ef4dd82e92
commit 0d0982b244

@ -15,7 +15,7 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode gitCommits versionCode gitCommits
versionName '0.2-b1' versionName '0.3'
buildConfigField 'String', 'GIT_BRANCH', "\"${gitBranch}\"" buildConfigField 'String', 'GIT_BRANCH', "\"${gitBranch}\""

@ -1,10 +1,12 @@
package org.koitharu.kotatsu.ui.settings package org.koitharu.kotatsu.ui.settings
import android.annotation.SuppressLint
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -22,8 +24,18 @@ import org.koitharu.kotatsu.core.github.VersionId
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.ui.common.BaseService import org.koitharu.kotatsu.ui.common.BaseService
import org.koitharu.kotatsu.utils.FileSizeUtils import org.koitharu.kotatsu.utils.FileSizeUtils
import org.koitharu.kotatsu.utils.ext.byte2HexFormatted
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateEncodingException
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class AppUpdateService : BaseService() { class AppUpdateService : BaseService() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -92,25 +104,26 @@ class AppUpdateService : BaseService() {
) )
builder.setSmallIcon(R.drawable.ic_stat_update) builder.setSmallIcon(R.drawable.ic_stat_update)
builder.setAutoCancel(true) builder.setAutoCancel(true)
builder.setColor(ContextCompat.getColor(this, R.color.blue_primary_dark)) builder.color = ContextCompat.getColor(this, R.color.blue_primary_dark)
builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)) builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
manager.notify(NOTIFICATION_ID, builder.build()) manager.notify(NOTIFICATION_ID, builder.build())
} }
companion object { companion object {
private const val CERT_SHA1 = "2C:19:C7:E8:07:61:2B:8E:94:51:1B:FD:72:67:07:64:5D:C2:58:AE"
private const val NOTIFICATION_ID = 202 private const val NOTIFICATION_ID = 202
private const val CHANNEL_ID = "update" private const val CHANNEL_ID = "update"
private val PERIOD = TimeUnit.HOURS.toMillis(6) private val PERIOD = TimeUnit.HOURS.toMillis(6)
fun start(context: Context) { fun isUpdateSupported(context: Context): Boolean {
try { return getCertificateSHA1Fingerprint(context) == CERT_SHA1
context.startService(Intent(context, AppUpdateService::class.java))
} catch (_: IllegalStateException) {
}
} }
fun startIfRequired(context: Context) { fun startIfRequired(context: Context) {
if (!isUpdateSupported(context)) {
return
}
val settings = AppSettings(context) val settings = AppSettings(context)
if (settings.appUpdateAuto) { if (settings.appUpdateAuto) {
val lastUpdate = settings.appUpdate val lastUpdate = settings.appUpdate
@ -119,5 +132,47 @@ class AppUpdateService : BaseService() {
} }
} }
} }
private fun start(context: Context) {
try {
context.startService(Intent(context, AppUpdateService::class.java))
} catch (_: IllegalStateException) {
}
}
@Suppress("DEPRECATION")
@SuppressLint("PackageManagerGetSignatures")
private fun getCertificateSHA1Fingerprint(context: Context): String? {
val packageInfo = try {
context.packageManager.getPackageInfo(
context.packageName,
PackageManager.GET_SIGNATURES
)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
return null
}
val signatures = packageInfo?.signatures
val cert: ByteArray = signatures?.firstOrNull()?.toByteArray() ?: return null
val input: InputStream = ByteArrayInputStream(cert)
val c = try {
val cf = CertificateFactory.getInstance("X509")
cf.generateCertificate(input) as X509Certificate
} catch (e: CertificateException) {
e.printStackTrace()
return null
}
return try {
val md: MessageDigest = MessageDigest.getInstance("SHA1")
val publicKey: ByteArray = md.digest(c.getEncoded())
publicKey.byte2HexFormatted()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
null
} catch (e: CertificateEncodingException) {
e.printStackTrace()
null
}
}
} }
} }

@ -37,6 +37,9 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
} }
findPreference<MultiSelectListPreference>(R.string.key_reader_switchers)?.summaryProvider = findPreference<MultiSelectListPreference>(R.string.key_reader_switchers)?.summaryProvider =
MultiSummaryProvider(R.string.gestures_only) MultiSummaryProvider(R.string.gestures_only)
findPreference<Preference>(R.string.key_app_update_auto)?.run {
isVisible = AppUpdateService.isUpdateSupported(context)
}
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.utils.ext
import android.net.Uri import android.net.Uri
import java.net.URLEncoder import java.net.URLEncoder
import java.util.*
fun String.longHashCode(): Long { fun String.longHashCode(): Long {
var h = 1125899906842597L var h = 1125899906842597L
@ -73,3 +74,22 @@ fun String.toUriOrNull(): Uri? = if (isEmpty()) {
} else { } else {
Uri.parse(this) Uri.parse(this)
} }
fun ByteArray.byte2HexFormatted(): String? {
val str = StringBuilder(size * 2)
for (i in indices) {
var h = Integer.toHexString(this[i].toInt())
val l = h.length
if (l == 1) {
h = "0$h"
}
if (l > 2) {
h = h.substring(l - 2, l)
}
str.append(h.toUpperCase(Locale.ROOT))
if (i < size - 1) {
str.append(':')
}
}
return str.toString()
}

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<ListPreference <ListPreference
android:defaultValue="-1" android:defaultValue="-1"
@ -32,9 +33,9 @@
<PreferenceScreen <PreferenceScreen
android:fragment="org.koitharu.kotatsu.ui.settings.sources.SourcesSettingsFragment" android:fragment="org.koitharu.kotatsu.ui.settings.sources.SourcesSettingsFragment"
android:key="@string/key_remote_sources"
android:title="@string/remote_sources" android:title="@string/remote_sources"
app:allowDividerAbove="true" app:allowDividerAbove="true"
android:key="@string/key_remote_sources"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<PreferenceScreen <PreferenceScreen
@ -53,8 +54,8 @@
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:title="@string/pages_animation"
android:key="@string/key_reader_animation" android:key="@string/key_reader_animation"
android:title="@string/pages_animation"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<PreferenceCategory <PreferenceCategory
@ -67,7 +68,9 @@
android:key="@string/key_app_update_auto" android:key="@string/key_app_update_auto"
android:summary="@string/show_notification_app_update" android:summary="@string/show_notification_app_update"
android:title="@string/application_update" android:title="@string/application_update"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false"
app:isPreferenceVisible="false"
tools:isPreferenceVisible="true" />
<SwitchPreference <SwitchPreference
android:defaultValue="true" android:defaultValue="true"
@ -77,10 +80,10 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<Preference <Preference
android:title="@string/notifications_settings"
app:iconSpaceReserved="false"
android:dependency="@string/key_tracker_notifications" android:dependency="@string/key_tracker_notifications"
android:key="@string/key_notifications_settings" /> android:key="@string/key_notifications_settings"
android:title="@string/notifications_settings"
app:iconSpaceReserved="false" />
</PreferenceCategory> </PreferenceCategory>

Loading…
Cancel
Save