Abrarul8541 commited on
Commit
ccfda31
·
verified ·
1 Parent(s): 7d2733b

Phase 5: in-app update check with SHA-256 verification

Browse files
app/src/main/java/io/github/abrarul/modularai/update/Updater.kt ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package io.github.abrarul.modularai.update
2
+
3
+ import io.github.abrarul.modularai.BuildConfig
4
+ import kotlinx.coroutines.Dispatchers
5
+ import kotlinx.coroutines.withContext
6
+ import org.json.JSONObject
7
+ import java.io.File
8
+ import java.net.URL
9
+ import java.security.MessageDigest
10
+
11
+ /**
12
+ * Manifest (JSON) hosted next to releases:
13
+ * {"versionCode":2,"versionName":"0.2.0","apk":"https://.../app.apk","sha256":"..."}
14
+ * Android itself refuses to install an update signed with a different key, which is the
15
+ * real signature check; SHA-256 guards against corrupt or tampered downloads.
16
+ */
17
+ data class UpdateInfo(val versionCode: Int, val versionName: String, val apkUrl: String, val sha256: String)
18
+
19
+ class Updater(private val manifestUrl: String, private val cacheDir: File) {
20
+
21
+ suspend fun check(): UpdateInfo? = withContext(Dispatchers.IO) {
22
+ val j = JSONObject(URL(manifestUrl).readText())
23
+ val info = UpdateInfo(j.getInt("versionCode"), j.getString("versionName"), j.getString("apk"), j.getString("sha256"))
24
+ if (info.versionCode > BuildConfig.VERSION_CODE) info else null
25
+ }
26
+
27
+ suspend fun download(info: UpdateInfo): File = withContext(Dispatchers.IO) {
28
+ val f = File(cacheDir, "update-${info.versionCode}.apk")
29
+ URL(info.apkUrl).openStream().use { i -> f.outputStream().use { o -> i.copyTo(o) } }
30
+ val md = MessageDigest.getInstance("SHA-256")
31
+ f.inputStream().use { i -> val b = ByteArray(1 shl 20); while (true) { val n = i.read(b); if (n < 0) break; md.update(b, 0, n) } }
32
+ val actual = md.digest().joinToString("") { "%02x".format(it) }
33
+ if (!actual.equals(info.sha256, ignoreCase = true)) { f.delete(); error("Update checksum mismatch") }
34
+ f
35
+ }
36
+ // Install hand-off (PackageInstaller / FileProvider) is the next task.
37
+ }