From 648c63bfbce5c33d0c18ba155aa4b3bbacb50a09 Mon Sep 17 00:00:00 2001 From: Song <168455@qq.com> Date: Fri, 10 Jul 2026 21:44:37 +0800 Subject: [PATCH] refactor: use plaintext Gitea URL instead of XOR+Base64 scramble - Gitea URL hardcoded as GITEA_API constant (no more release-notes discovery) - Removed parseUpdateSource / unscramble / SCRAMBLE_KEY - Release notes no longer need update-source comment - version 1.9.4 -> 1.9.5 (code 33 -> 34) Co-Authored-By: Claude Opus 4.8 (1M context) --- app/build.gradle.kts | 4 +-- .../com/a2i/forwarder/core/UpdateChecker.kt | 32 ++++--------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6599d61..1ac44ee 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "com.a2i.forwarder" minSdk = 34 targetSdk = 36 - versionCode = 33 - versionName = "1.9.4" + versionCode = 34 + versionName = "1.9.5" } signingConfigs { diff --git a/app/src/main/java/com/a2i/forwarder/core/UpdateChecker.kt b/app/src/main/java/com/a2i/forwarder/core/UpdateChecker.kt index 8250a90..1a2e48b 100644 --- a/app/src/main/java/com/a2i/forwarder/core/UpdateChecker.kt +++ b/app/src/main/java/com/a2i/forwarder/core/UpdateChecker.kt @@ -70,19 +70,15 @@ class UpdateChecker(private val context: Context) { val now = System.currentTimeMillis() if (throttle && now - settings.lastUpdateCheckTime.value < CHECK_INTERVAL_MS) return@runCatching updateInfo.value - // 先查 GitHub(公开默认源),从其 release notes 动态发现额外源(如自建 Gitea),取最高版本 + // 双源查询:Gitea(国内优先)+ GitHub(备用),取最高版本 // 同版本时 Gitea 优先(国内可达,GitHub 可能被墙导致下载失败) val infos = mutableListOf() var ghInfo: UpdateInfo? = null var giteaInfo: UpdateInfo? = null - val gh = runCatching { fetchRelease(GITHUB_API) }.getOrNull() - if (gh != null) { - ghInfo = gh - giteaInfo = parseUpdateSource(gh.releaseNotes)?.let { runCatching { fetchRelease(it) }.getOrNull() } - // Gitea 放前面,同版本时优先用它下载(国内可达) - if (giteaInfo != null) infos.add(giteaInfo) - infos.add(gh) - } + giteaInfo = runCatching { fetchRelease(GITEA_API) }.getOrNull() + if (giteaInfo != null) infos.add(giteaInfo) + ghInfo = runCatching { fetchRelease(GITHUB_API) }.getOrNull() + if (ghInfo != null) infos.add(ghInfo) settings.setLastUpdateCheck(now) if (infos.isEmpty()) { lastError.value = "所有更新源不可达" @@ -303,26 +299,10 @@ class UpdateChecker(private val context: Context) { return false } - /** 从 release notes 的 HTML 注释里解析额外更新源(加扰编码,兼容 Base64/明文)。 */ - private fun parseUpdateSource(body: String): String? { - val raw = Regex("""update-source:\s*(\S+)""").find(body)?.groupValues?.getOrNull(1) ?: return null - // 加扰格式:Base64(反转(XOR(明文, key)))。尝试完整解扰,失败则依次尝试 Base64/明文。 - val b64 = runCatching { java.util.Base64.getDecoder().decode(raw) }.getOrNull() ?: return raw - val unscrambled = unscramble(b64) - return unscrambled ?: runCatching { String(b64, Charsets.UTF_8) }.getOrNull() ?: raw - } - - /** 解扰:反转字节 → XOR 每字节 → UTF-8 字符串。 */ - private fun unscramble(data: ByteArray): String? = runCatching { - val key = SCRAMBLE_KEY - val reversed = data.reversedArray() - String(ByteArray(reversed.size) { i -> ((reversed[i].toInt() and 0xFF) xor (key[i % key.size].toInt() and 0xFF)).toByte() }, Charsets.UTF_8) - }.getOrNull() - companion object { const val GITHUB_API = "https://api.github.com/repos/lsxf/a2i/releases/latest" + const val GITEA_API = "https://gitea.songer.eu.org/api/v1/repos/song/a2i/releases/latest" const val CHECK_INTERVAL_MS = 24L * 60 * 60 * 1000 - private val SCRAMBLE_KEY = byteArrayOf(0x4B, 0x6F, 0x72, 0x6E) // "Korn" } fun formatSize(bytes: Long): String {