fix: 安全与发布成熟度改进
1. 移除通用 WebView 登录入口(半成品功能,凭据无法正确映射到 Repository) 2. allowBackup=false,移除空模板备份规则引用 3. 版本号修正:versionCode=5, versionName=1.5 4. 签名密码默认值改为空字符串(CI 注入 Secret) 5. release workflow 注入签名密码环境变量 6. 新增 ci.yml:push/PR 触发单测+Debug 编译 7. 新增 LICENSE 文件(MIT) 8. CommandCodeGoRepository 注释修正(顺序执行非并行) 9. README 安全声明更新}
This commit is contained in:
parent
0b140fe73e
commit
5178af91f6
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
- uses: android-actions/setup-android@v3
|
||||||
|
with:
|
||||||
|
packages: 'platforms;android-35 build-tools;35.0.0'
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew testDebugUnitTest
|
||||||
|
- name: Assemble Debug
|
||||||
|
run: ./gradlew assembleDebug
|
||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -21,6 +21,10 @@ jobs:
|
|||||||
- name: Decode Keystore
|
- name: Decode Keystore
|
||||||
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > release.jks
|
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > release.jks
|
||||||
- name: Build Release APK
|
- name: Build Release APK
|
||||||
|
env:
|
||||||
|
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||||
|
KEYSTORE_ALIAS: ${{ secrets.KEYSTORE_ALIAS }}
|
||||||
|
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
chmod +x gradlew
|
chmod +x gradlew
|
||||||
./gradlew assembleRelease
|
./gradlew assembleRelease
|
||||||
|
|||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Rainy
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@ -185,9 +185,9 @@ chmod +x ./setup_android_env.sh
|
|||||||
|
|
||||||
- ✅ API Key / Session 凭据存入 **Android Keystore**(AES-256 GCM 加密)
|
- ✅ API Key / Session 凭据存入 **Android Keystore**(AES-256 GCM 加密)
|
||||||
- ✅ 网络请求仅向 DeepSeek / OpenCode 官方 API 发出
|
- ✅ 网络请求仅向 DeepSeek / OpenCode 官方 API 发出
|
||||||
- ✅ API Key / Session 由 Android Keystore 加密;应用数据备份规则由 `data_extraction_rules.xml` / `backup_rules.xml` 控制
|
- ✅ `allowBackup=false`:凭据密文、用量数据均不参与系统备份,避免换机恢复后密文无法解密
|
||||||
- ✅ 签名密钥固定,每次 Release 可覆盖安装
|
- ✅ 签名密钥固定,每次 Release 可覆盖安装
|
||||||
- ✅ GitHub Secrets 加密存储签名密钥,CI 中解码使用
|
- ✅ GitHub Secrets 加密存储签名密钥及密码,CI 中解码使用
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,8 @@ android {
|
|||||||
applicationId = "com.rainy.token"
|
applicationId = "com.rainy.token"
|
||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 5
|
||||||
versionName = "1.0"
|
versionName = "1.5"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
@ -26,9 +26,9 @@ android {
|
|||||||
signingConfigs {
|
signingConfigs {
|
||||||
create("release") {
|
create("release") {
|
||||||
storeFile = rootProject.file("release.jks")
|
storeFile = rootProject.file("release.jks")
|
||||||
storePassword = System.getenv("KEYSTORE_PASSWORD") ?: "RainyToken2026!"
|
storePassword = System.getenv("KEYSTORE_PASSWORD") ?: ""
|
||||||
keyAlias = System.getenv("KEYSTORE_ALIAS") ?: "rainy"
|
keyAlias = System.getenv("KEYSTORE_ALIAS") ?: "rainy"
|
||||||
keyPassword = System.getenv("KEY_PASSWORD") ?: "RainyToken2026!"
|
keyPassword = System.getenv("KEY_PASSWORD") ?: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,10 +7,8 @@
|
|||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".RainyTokenApplication"
|
android:name=".RainyTokenApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="false"
|
||||||
android:enableOnBackInvokedCallback="true"
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class CommandCodeGoRepository(
|
|||||||
return@withContext Result.failure(RepositoryError.InvalidCredential())
|
return@withContext Result.failure(RepositoryError.InvalidCredential())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 并行拉取 credits + subscriptions
|
// 顺序拉取 credits + subscriptions(credits 是主要数据源,subscription 用于补充计划信息)
|
||||||
val creditsResult = runCatching { fetchCredits(apiKey) }
|
val creditsResult = runCatching { fetchCredits(apiKey) }
|
||||||
val subResult = runCatching { fetchSubscription(apiKey) }
|
val subResult = runCatching { fetchSubscription(apiKey) }
|
||||||
|
|
||||||
|
|||||||
@ -1003,7 +1003,7 @@ private fun ActionButtons(
|
|||||||
Text("刷新余额")
|
Text("刷新余额")
|
||||||
}
|
}
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = onStartWebViewLogin,
|
onClick = onConfigureCredential,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text("重新登录")
|
Text("重新登录")
|
||||||
|
|||||||
@ -171,7 +171,8 @@ fun CredentialEditScreen(
|
|||||||
onShowHelp = { showGoHelp = true }
|
onShowHelp = { showGoHelp = true }
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// 通用 WebView 抓取 / 手动模式
|
// 通用 WebView 抓取已移除(半成品功能,凭据无法正确映射到 Repository 字段)
|
||||||
|
// 保留手动 Cookie 粘贴作为 fallback
|
||||||
ManualCookieForm(
|
ManualCookieForm(
|
||||||
cookieValue = uiState.cookieInput,
|
cookieValue = uiState.cookieInput,
|
||||||
onCookieChange = viewModel::updateCookieInput,
|
onCookieChange = viewModel::updateCookieInput,
|
||||||
@ -184,12 +185,6 @@ fun CredentialEditScreen(
|
|||||||
},
|
},
|
||||||
onShowHelp = { showCookieHelp = true }
|
onShowHelp = { showCookieHelp = true }
|
||||||
)
|
)
|
||||||
OutlinedButton(
|
|
||||||
onClick = { onStartWebViewLogin(service) },
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(text = "尝试 WebView 登录(备用)")
|
|
||||||
}
|
|
||||||
if (uiState.hasExisting) {
|
if (uiState.hasExisting) {
|
||||||
Text(
|
Text(
|
||||||
text = "✓ 已配置登录态(${uiState.cookieCount} 个 Cookie)",
|
text = "✓ 已配置登录态(${uiState.cookieCount} 个 Cookie)",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user