From a69dd69aa7d25356b9b824d769928ecb0b7ba94c Mon Sep 17 00:00:00 2001 From: LinBeitsi <58358419+NevadaCities@users.noreply.github.com> Date: Thu, 4 Jun 2026 21:00:32 +0800 Subject: [PATCH] feat(profile): support age secret keys (#764) --- .../kr328/clash/ExternalControlActivity.kt | 4 +- .../github/kr328/clash/PropertiesActivity.kt | 4 +- core/src/main/cpp/main.c | 23 +++++-- core/src/main/golang/native/config.go | 13 +++- core/src/main/golang/native/config/age.go | 7 ++ .../java/com/github/kr328/clash/core/Clash.kt | 4 ++ .../github/kr328/clash/core/bridge/Bridge.kt | 2 + .../kr328/clash/design/PropertiesDesign.kt | 17 +++++ .../kr328/clash/design/util/Validator.kt | 4 ++ .../src/main/res/drawable/ic_baseline_key.xml | 3 + .../src/main/res/layout/design_properties.xml | 10 +++ design/src/main/res/values-ja-rJP/strings.xml | 3 + design/src/main/res/values-ko-rKR/strings.xml | 3 + design/src/main/res/values-ru/strings.xml | 3 + design/src/main/res/values-vi/strings.xml | 3 + design/src/main/res/values-zh-rHK/strings.xml | 3 + design/src/main/res/values-zh-rTW/strings.xml | 3 + design/src/main/res/values-zh/strings.xml | 3 + design/src/main/res/values/strings.xml | 3 + .../kr328/clash/service/ProfileManager.kt | 40 ++++++----- .../kr328/clash/service/ProfileProcessor.kt | 66 +++++++++---------- .../clash/module/ConfigurationModule.kt | 4 +- .../kr328/clash/service/data/Database.kt | 4 +- .../kr328/clash/service/data/Imported.kt | 1 + .../kr328/clash/service/data/Pending.kt | 1 + .../service/data/migrations/Migrations.kt | 14 +++- .../kr328/clash/service/document/Picker.kt | 3 +- .../kr328/clash/service/model/Profile.kt | 5 +- .../clash/service/remote/IProfileManager.kt | 6 +- 29 files changed, 187 insertions(+), 72 deletions(-) create mode 100644 core/src/main/golang/native/config/age.go create mode 100644 design/src/main/res/drawable/ic_baseline_key.xml diff --git a/app/src/main/java/com/github/kr328/clash/ExternalControlActivity.kt b/app/src/main/java/com/github/kr328/clash/ExternalControlActivity.kt index ba80d038..2f451ebf 100644 --- a/app/src/main/java/com/github/kr328/clash/ExternalControlActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/ExternalControlActivity.kt @@ -47,7 +47,7 @@ class ExternalControlActivity : Activity(), CoroutineScope by MainScope() { val intervalMs = java.util.concurrent.TimeUnit.MINUTES.toMillis(updateInterval) create(type, name).also { - patch(it, name, url, intervalMs) + patch(it, name, url, intervalMs, null) } } startActivity(PropertiesActivity::class.intent.setUUID(uuid)) @@ -103,4 +103,4 @@ class ExternalControlActivity : Activity(), CoroutineScope by MainScope() { @Suppress("DEPRECATION") overridePendingTransition(0, 0) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/github/kr328/clash/PropertiesActivity.kt b/app/src/main/java/com/github/kr328/clash/PropertiesActivity.kt index 62adc8bc..a6fc0755 100644 --- a/app/src/main/java/com/github/kr328/clash/PropertiesActivity.kt +++ b/app/src/main/java/com/github/kr328/clash/PropertiesActivity.kt @@ -45,7 +45,7 @@ class PropertiesActivity : BaseActivity() { if (!canceled && profile != original) { withProfile { - patch(profile.uuid, profile.name, profile.source, profile.interval) + patch(profile.uuid, profile.name, profile.source, profile.interval, profile.ageSecretKey) } } } @@ -92,7 +92,7 @@ class PropertiesActivity : BaseActivity() { try { withProcessing { updateStatus -> withProfile { - patch(profile.uuid, profile.name, profile.source, profile.interval) + patch(profile.uuid, profile.name, profile.source, profile.interval, profile.ageSecretKey) coroutineScope { commit(profile.uuid) { diff --git a/core/src/main/cpp/main.c b/core/src/main/cpp/main.c index 914bf7d9..20c5a46b 100644 --- a/core/src/main/cpp/main.c +++ b/core/src/main/cpp/main.c @@ -226,9 +226,9 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeLoad(JNIEnv *env, jobject t JNIEXPORT void JNICALL Java_com_github_kr328_clash_core_bridge_Bridge_nativeFetchAndValid(JNIEnv *env, jobject thiz, - jobject callback, - jstring path, - jstring url, jboolean force) { + jobject callback, + jstring path, + jstring url, jboolean force) { TRACE_METHOD(); jobject _completable = new_global(callback); @@ -238,6 +238,21 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeFetchAndValid(JNIEnv *env, fetchAndValid(_completable, _path, _url, force); } +JNIEXPORT void JNICALL +Java_com_github_kr328_clash_core_bridge_Bridge_nativeSetAgeSecretKey(JNIEnv *env, jobject thiz, + jstring key) { + TRACE_METHOD(); + + if (key == NULL) { + setAgeSecretKey(NULL); + return; + } + + scoped_string _key = get_string(key); + + setAgeSecretKey(_key); +} + JNIEXPORT jstring JNICALL Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryProviders(JNIEnv *env, jobject thiz) { TRACE_METHOD(); @@ -526,4 +541,4 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeCoreVersion(JNIEnv *env, jo char* Version = make_String(GIT_VERSION); return new_string(Version); -} \ No newline at end of file +} diff --git a/core/src/main/golang/native/config.go b/core/src/main/golang/native/config.go index f1e41606..6338bd13 100644 --- a/core/src/main/golang/native/config.go +++ b/core/src/main/golang/native/config.go @@ -59,4 +59,15 @@ func writeOverride(slot C.int, content C.c_string) { //export clearOverride func clearOverride(slot C.int) { config.ClearOverride(config.OverrideSlot(slot)) -} \ No newline at end of file +} + +//export setAgeSecretKey +func setAgeSecretKey(key C.c_string) { + if key == nil { + config.SetGlobalSecretKeys() + return + } + + k := C.GoString(key) + config.SetGlobalSecretKeys(k) +} diff --git a/core/src/main/golang/native/config/age.go b/core/src/main/golang/native/config/age.go new file mode 100644 index 00000000..5348dd83 --- /dev/null +++ b/core/src/main/golang/native/config/age.go @@ -0,0 +1,7 @@ +package config + +import "github.com/metacubex/mihomo/component/age" + +func SetGlobalSecretKeys(secretKeys ...string) { + age.SetGlobalSecretKeys(secretKeys...) +} diff --git a/core/src/main/java/com/github/kr328/clash/core/Clash.kt b/core/src/main/java/com/github/kr328/clash/core/Clash.kt index a3be5fa5..bc878223 100644 --- a/core/src/main/java/com/github/kr328/clash/core/Clash.kt +++ b/core/src/main/java/com/github/kr328/clash/core/Clash.kt @@ -225,4 +225,8 @@ object Clash { }) } } + + fun setAgeSecretKey(key: String?) { + Bridge.nativeSetAgeSecretKey(key) + } } \ No newline at end of file diff --git a/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt b/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt index 66df597d..6007ff1d 100644 --- a/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt +++ b/core/src/main/java/com/github/kr328/clash/core/bridge/Bridge.kt @@ -50,6 +50,8 @@ object Bridge { external fun nativeSubscribeLogcat(callback: LogcatInterface) external fun nativeCoreVersion(): String + external fun nativeSetAgeSecretKey(key: String?) + private external fun nativeInit(home: String, versionName: String, sdkVersion: Int) init { diff --git a/design/src/main/java/com/github/kr328/clash/design/PropertiesDesign.kt b/design/src/main/java/com/github/kr328/clash/design/PropertiesDesign.kt index e18fafdf..c3b5d56e 100644 --- a/design/src/main/java/com/github/kr328/clash/design/PropertiesDesign.kt +++ b/design/src/main/java/com/github/kr328/clash/design/PropertiesDesign.kt @@ -121,6 +121,23 @@ class PropertiesDesign(context: Context) : Design(cont } } + fun inputAgeSecretKey() { + launch { + val ageSecretKey = context.requestModelTextInput( + initial = profile.ageSecretKey ?: "", + title = context.getText(R.string.age_secret_key), + hint = context.getText(R.string.age_secret_key_hint), + error = context.getText(R.string.age_secret_key_error), + validator = ValidatorAgeSecretKey + ) + + val newKey = ageSecretKey.ifBlank { null } + if (newKey != profile.ageSecretKey) { + profile = profile.copy(ageSecretKey = newKey) + } + } + } + fun inputInterval() { launch { var minutes = TimeUnit.MILLISECONDS.toMinutes(profile.interval) diff --git a/design/src/main/java/com/github/kr328/clash/design/util/Validator.kt b/design/src/main/java/com/github/kr328/clash/design/util/Validator.kt index f78f6e42..8fa87232 100644 --- a/design/src/main/java/com/github/kr328/clash/design/util/Validator.kt +++ b/design/src/main/java/com/github/kr328/clash/design/util/Validator.kt @@ -22,4 +22,8 @@ val ValidatorHttpUrl: Validator = { val ValidatorAutoUpdateInterval: Validator = { it.isEmpty() || (it.toLongOrNull() ?: 0) >= 15 +} + +val ValidatorAgeSecretKey: Validator = { + it.isEmpty() || it.startsWith("AGE-SECRET-KEY-", ignoreCase = true) } \ No newline at end of file diff --git a/design/src/main/res/drawable/ic_baseline_key.xml b/design/src/main/res/drawable/ic_baseline_key.xml new file mode 100644 index 00000000..d2cd6f11 --- /dev/null +++ b/design/src/main/res/drawable/ic_baseline_key.xml @@ -0,0 +1,3 @@ + + + diff --git a/design/src/main/res/layout/design_properties.xml b/design/src/main/res/layout/design_properties.xml index b037d95c..a234bba2 100644 --- a/design/src/main/res/layout/design_properties.xml +++ b/design/src/main/res/layout/design_properties.xml @@ -77,6 +77,16 @@ app:text="@{profile.source}" app:title="@string/url" /> + + http(s) のみを許可 15分以上か空白にしてください 空白にはできません + Age秘密鍵 + AGE-SECRET-KEY-…(任意) + フォーマットが無効です。鍵は AGE-SECRET-KEY- で始まる必要があります 詳細 更新 編集 diff --git a/design/src/main/res/values-ko-rKR/strings.xml b/design/src/main/res/values-ko-rKR/strings.xml index ab0bbf0a..5e858be6 100644 --- a/design/src/main/res/values-ko-rKR/strings.xml +++ b/design/src/main/res/values-ko-rKR/strings.xml @@ -47,6 +47,9 @@ http(s) 연결만 허용 최소 15분 이상 또는 공백 이 필드는 공백이 허용되지 않습니다. + Age 비밀 키 + AGE-SECRET-KEY-…(선택사항) + 잘못된 형식입니다. 키는 AGE-SECRET-KEY- 로 시작해야 합니다 자세히 업데이트 편집 diff --git a/design/src/main/res/values-ru/strings.xml b/design/src/main/res/values-ru/strings.xml index 342b639d..f81525e3 100644 --- a/design/src/main/res/values-ru/strings.xml +++ b/design/src/main/res/values-ru/strings.xml @@ -57,6 +57,9 @@ Принимать только http(s) Не менее 15 минут или пустой Не должно быть пустым + Секретный ключ Age + AGE-SECRET-KEY-… (необязательно) + Неверный формат. Ключ должен начинаться с AGE-SECRET-KEY- Детали Обновить Изменить diff --git a/design/src/main/res/values-vi/strings.xml b/design/src/main/res/values-vi/strings.xml index 2bf8aaca..fd337de6 100644 --- a/design/src/main/res/values-vi/strings.xml +++ b/design/src/main/res/values-vi/strings.xml @@ -25,6 +25,9 @@ Các gói kiểm soát truy cập Định cấu hình quyền truy cập cho các ứng dụng Hồ sơ cần được lưu trước khi kích hoạt + Khóa bí mật Age + AGE-SECRET-KEY-… (tùy chọn) + Định dạng không hợp lệ. Khóa phải bắt đầu bằng AGE-SECRET-KEY- Cho phép tất cả các ứng dụng Cho phép bỏ qua Cho phép tất cả các ứng dụng bỏ qua kết nối VPN này diff --git a/design/src/main/res/values-zh-rHK/strings.xml b/design/src/main/res/values-zh-rHK/strings.xml index 537b33f3..9a83b6e0 100644 --- a/design/src/main/res/values-zh-rHK/strings.xml +++ b/design/src/main/res/values-zh-rHK/strings.xml @@ -78,6 +78,9 @@ 更新時間 應用包名稱 安裝時間 + Age 私鑰 + AGE-SECRET-KEY-…(可選) + 格式無效。密鑰應以 AGE-SECRET-KEY- 開頭 反饋 Github Issues Clash 配置文件(包含代理/規則)]]> diff --git a/design/src/main/res/values-zh-rTW/strings.xml b/design/src/main/res/values-zh-rTW/strings.xml index cf70cc2d..feca4582 100644 --- a/design/src/main/res/values-zh-rTW/strings.xml +++ b/design/src/main/res/values-zh-rTW/strings.xml @@ -78,6 +78,9 @@ 更新時間 套件名稱 安裝時間 + Age 私鑰 + AGE-SECRET-KEY-…(選填) + 格式無效。金鑰應以 AGE-SECRET-KEY- 開頭 回饋 Github Issues Clash 設定檔 (包含Proxy /規則)]]> diff --git a/design/src/main/res/values-zh/strings.xml b/design/src/main/res/values-zh/strings.xml index 31c13719..09de0724 100644 --- a/design/src/main/res/values-zh/strings.xml +++ b/design/src/main/res/values-zh/strings.xml @@ -78,6 +78,9 @@ VpnService 选项 选项在 Clash 运行时不可用 查找 + Age 私钥 + AGE-SECRET-KEY-…(可选) + 格式无效。密钥应以 AGE-SECRET-KEY- 开头 系统应用 更新时间 应用包名称 diff --git a/design/src/main/res/values/strings.xml b/design/src/main/res/values/strings.xml index 0808ae4b..f4afaa29 100644 --- a/design/src/main/res/values/strings.xml +++ b/design/src/main/res/values/strings.xml @@ -62,6 +62,9 @@ Accept only http(s) At least 15 minutes or empty + Age Secret Key + AGE-SECRET-KEY-… (optional) + Invalid format. Key should start with AGE-SECRET-KEY- Should not be blank Detail Update diff --git a/service/src/main/java/com/github/kr328/clash/service/ProfileManager.kt b/service/src/main/java/com/github/kr328/clash/service/ProfileManager.kt index 848dd3d2..b5f1e1e3 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ProfileManager.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ProfileManager.kt @@ -37,7 +37,7 @@ class ProfileManager(private val context: Context) : IProfileManager, } } - override suspend fun create(type: Profile.Type, name: String, source: String): UUID { + override suspend fun create(type: Profile.Type, name: String, source: String, ageSecretKey: String?): UUID { val uuid = generateProfileUUID() val pending = Pending( uuid = uuid, @@ -49,6 +49,7 @@ class ProfileManager(private val context: Context) : IProfileManager, total = 0, download = 0, expire = 0, + ageSecretKey = ageSecretKey, ) PendingDao().insert(pending) @@ -81,6 +82,7 @@ class ProfileManager(private val context: Context) : IProfileManager, total = imported.total, download = imported.download, expire = imported.expire, + ageSecretKey = imported.ageSecretKey ) cloneImportedFiles(uuid, newUUID) @@ -90,7 +92,7 @@ class ProfileManager(private val context: Context) : IProfileManager, return newUUID } - override suspend fun patch(uuid: UUID, name: String, source: String, interval: Long) { + override suspend fun patch(uuid: UUID, name: String, source: String, interval: Long, ageSecretKey: String?) { val pending = PendingDao().queryByUUID(uuid) if (pending == null) { @@ -110,6 +112,7 @@ class ProfileManager(private val context: Context) : IProfileManager, total = 0, download = 0, expire = 0, + ageSecretKey = ageSecretKey, ) ) } else { @@ -121,6 +124,7 @@ class ProfileManager(private val context: Context) : IProfileManager, total = 0, download = 0, expire = 0, + ageSecretKey = ageSecretKey, ) PendingDao().update(newPending) @@ -188,7 +192,8 @@ class ProfileManager(private val context: Context) : IProfileManager, download, total, expire, - old?.createdAt ?: System.currentTimeMillis() + old?.createdAt ?: System.currentTimeMillis(), + ageSecretKey = old.ageSecretKey ) if (old != null) { @@ -266,19 +271,20 @@ class ProfileManager(private val context: Context) : IProfileManager, val expire = pending?.expire ?: imported?.expire ?: return null return Profile( - uuid, - name, - type, - source, - active != null && imported?.uuid == active, - interval, - upload, - download, - total, - expire, - resolveUpdatedAt(uuid), - imported != null, - pending != null + uuid = uuid, + name = name, + type = type, + source = source, + active = active != null && imported?.uuid == active, + interval = interval, + upload = upload, + download = download, + total = total, + expire = expire, + updatedAt = resolveUpdatedAt(uuid), + imported = imported != null, + pending = pending != null, + ageSecretKey = if (pending != null) pending.ageSecretKey else imported?.ageSecretKey, ) } @@ -309,4 +315,4 @@ class ProfileManager(private val context: Context) : IProfileManager, ProfileReceiver.scheduleNext(context, imported) } } -} \ No newline at end of file +} diff --git a/service/src/main/java/com/github/kr328/clash/service/ProfileProcessor.kt b/service/src/main/java/com/github/kr328/clash/service/ProfileProcessor.kt index 710f5d48..6ad62769 100644 --- a/service/src/main/java/com/github/kr328/clash/service/ProfileProcessor.kt +++ b/service/src/main/java/com/github/kr328/clash/service/ProfileProcessor.kt @@ -22,7 +22,6 @@ import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import okhttp3.Request import java.math.BigDecimal -import java.net.URL import java.util.* import java.util.concurrent.TimeUnit @@ -34,8 +33,8 @@ object ProfileProcessor { withContext(NonCancellable) { processLock.withLock { val snapshot = profileLock.withLock { - val pending = PendingDao().queryByUUID(uuid) - ?: throw IllegalArgumentException("profile $uuid not found") + val pending = + PendingDao().queryByUUID(uuid) ?: throw IllegalArgumentException("profile $uuid not found") pending.enforceFieldValid() @@ -48,6 +47,8 @@ object ProfileProcessor { pending } + Clash.setAgeSecretKey(snapshot.ageSecretKey?.takeIf { it.isNotBlank() }) + val force = snapshot.type != Profile.Type.File var cb = callback @@ -63,10 +64,8 @@ object ProfileProcessor { profileLock.withLock { if (PendingDao().queryByUUID(snapshot.uuid) == snapshot) { - context.importedDir.resolve(snapshot.uuid.toString()) - .deleteRecursively() - context.processingDir - .copyRecursively(context.importedDir.resolve(snapshot.uuid.toString())) + context.importedDir.resolve(snapshot.uuid.toString()).deleteRecursively() + context.processingDir.copyRecursively(context.importedDir.resolve(snapshot.uuid.toString())) val old = ImportedDao().queryByUUID(snapshot.uuid) var upload: Long = 0 @@ -77,11 +76,10 @@ object ProfileProcessor { if (snapshot?.type == Profile.Type.Url) { if (snapshot.source.startsWith("https://", true)) { val client = OkHttpClient() - val versionName = context.packageManager.getPackageInfo(context.packageName, 0).versionName - val request = Request.Builder() - .url(snapshot.source) - .header("User-Agent", "ClashMetaForAndroid/$versionName") - .build() + val versionName = + context.packageManager.getPackageInfo(context.packageName, 0).versionName + val request = Request.Builder().url(snapshot.source) + .header("User-Agent", "ClashMetaForAndroid/$versionName").build() client.newCall(request).execute().use { response -> val userinfo = response.headers["subscription-userinfo"] @@ -99,7 +97,7 @@ object ProfileProcessor { info[0].contains("total") && info[1].isNotEmpty() -> total = BigDecimal(info[1].split('.').first()).longValueExact() - info[0].contains("expire") && info[1].isNotEmpty() -> expire = + info[0].contains("expire") && info[1].isNotEmpty() -> expire = (info[1].toDouble() * 1000).toLong() } } @@ -110,8 +108,8 @@ object ProfileProcessor { val intervalHours = updateIntervalHeader.toLongOrNull() if (intervalHours != null) { updateInterval = if (intervalHours > 0) { - java.util.concurrent.TimeUnit.HOURS.toMillis(intervalHours) - .coerceAtLeast(java.util.concurrent.TimeUnit.MINUTES.toMillis(15)) + TimeUnit.HOURS.toMillis(intervalHours) + .coerceAtLeast(TimeUnit.MINUTES.toMillis(15)) } else { 0L } @@ -129,7 +127,8 @@ object ProfileProcessor { download, total, expire, - old?.createdAt ?: System.currentTimeMillis() + old?.createdAt ?: System.currentTimeMillis(), + ageSecretKey = snapshot.ageSecretKey ) if (old != null) { ImportedDao().update(new) @@ -139,8 +138,7 @@ object ProfileProcessor { PendingDao().remove(snapshot.uuid) - context.pendingDir.resolve(snapshot.uuid.toString()) - .deleteRecursively() + context.pendingDir.resolve(snapshot.uuid.toString()).deleteRecursively() context.sendProfileChanged(snapshot.uuid) } else if (snapshot?.type == Profile.Type.File) { @@ -154,7 +152,8 @@ object ProfileProcessor { download, total, expire, - old?.createdAt ?: System.currentTimeMillis() + old?.createdAt ?: System.currentTimeMillis(), + ageSecretKey = snapshot.ageSecretKey ) if (old != null) { ImportedDao().update(new) @@ -164,8 +163,7 @@ object ProfileProcessor { PendingDao().remove(snapshot.uuid) - context.pendingDir.resolve(snapshot.uuid.toString()) - .deleteRecursively() + context.pendingDir.resolve(snapshot.uuid.toString()).deleteRecursively() context.sendProfileChanged(snapshot.uuid) } @@ -179,8 +177,8 @@ object ProfileProcessor { withContext(NonCancellable) { processLock.withLock { val snapshot = profileLock.withLock { - val imported = ImportedDao().queryByUUID(uuid) - ?: throw IllegalArgumentException("profile $uuid not found") + val imported = + ImportedDao().queryByUUID(uuid) ?: throw IllegalArgumentException("profile $uuid not found") context.processingDir.deleteRecursively() context.processingDir.mkdirs() @@ -191,6 +189,8 @@ object ProfileProcessor { imported } + Clash.setAgeSecretKey(snapshot.ageSecretKey?.takeIf { it.isNotBlank() }) + var cb = callback Clash.fetchAndValid(context.processingDir, snapshot.source, true) { @@ -206,8 +206,7 @@ object ProfileProcessor { profileLock.withLock { if (ImportedDao().exists(snapshot.uuid)) { context.importedDir.resolve(snapshot.uuid.toString()).deleteRecursively() - context.processingDir - .copyRecursively(context.importedDir.resolve(snapshot.uuid.toString())) + context.processingDir.copyRecursively(context.importedDir.resolve(snapshot.uuid.toString())) context.sendProfileChanged(snapshot.uuid) } @@ -261,17 +260,16 @@ object ProfileProcessor { val scheme = Uri.parse(source)?.scheme?.lowercase(Locale.getDefault()) when { - name.isBlank() -> - throw IllegalArgumentException("Empty name") + name.isBlank() -> throw IllegalArgumentException("Empty name") - source.isEmpty() && type != Profile.Type.File -> - throw IllegalArgumentException("Invalid url") + source.isEmpty() && type != Profile.Type.File -> throw IllegalArgumentException("Invalid url") - source.isNotEmpty() && scheme != "https" && scheme != "http" && scheme != "content" -> - throw IllegalArgumentException("Unsupported url $source") + source.isNotEmpty() && scheme != "https" && scheme != "http" && scheme != "content" -> throw IllegalArgumentException( + "Unsupported url $source" + ) - interval != 0L && TimeUnit.MILLISECONDS.toMinutes(interval) < 15 -> - throw IllegalArgumentException("Invalid interval") + interval != 0L && TimeUnit.MILLISECONDS.toMinutes(interval) < 15 -> throw IllegalArgumentException("Invalid interval") } } -} \ No newline at end of file + +} diff --git a/service/src/main/java/com/github/kr328/clash/service/clash/module/ConfigurationModule.kt b/service/src/main/java/com/github/kr328/clash/service/clash/module/ConfigurationModule.kt index 4e384b46..7de311aa 100644 --- a/service/src/main/java/com/github/kr328/clash/service/clash/module/ConfigurationModule.kt +++ b/service/src/main/java/com/github/kr328/clash/service/clash/module/ConfigurationModule.kt @@ -55,6 +55,8 @@ class ConfigurationModule(service: Service) : Module = arrayOf() +private val MIGRATION_1_2 = object : Migration(1, 2) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE imported ADD COLUMN ageSecretKey TEXT") + database.execSQL("ALTER TABLE pending ADD COLUMN ageSecretKey TEXT") + } +} -val LEGACY_MIGRATION = ::migrationFromLegacy \ No newline at end of file +val MIGRATIONS: Array = arrayOf( + MIGRATION_1_2, +) + +val LEGACY_MIGRATION = ::migrationFromLegacy diff --git a/service/src/main/java/com/github/kr328/clash/service/document/Picker.kt b/service/src/main/java/com/github/kr328/clash/service/document/Picker.kt index aa08829c..7eaa9e2a 100644 --- a/service/src/main/java/com/github/kr328/clash/service/document/Picker.kt +++ b/service/src/main/java/com/github/kr328/clash/service/document/Picker.kt @@ -134,7 +134,8 @@ class Picker(private val context: Context) { imported.type, imported.source, imported.interval, - 0,0,0,0 + 0,0,0,0, + ageSecretKey = imported.ageSecretKey ) ) diff --git a/service/src/main/java/com/github/kr328/clash/service/model/Profile.kt b/service/src/main/java/com/github/kr328/clash/service/model/Profile.kt index 4c2b4980..436894ad 100644 --- a/service/src/main/java/com/github/kr328/clash/service/model/Profile.kt +++ b/service/src/main/java/com/github/kr328/clash/service/model/Profile.kt @@ -22,11 +22,10 @@ data class Profile( var download: Long, val total: Long, val expire: Long, - - val updatedAt: Long, val imported: Boolean, val pending: Boolean, + val ageSecretKey: String? = null, ) : Parcelable { enum class Type { File, Url, External @@ -49,4 +48,4 @@ data class Profile( return arrayOfNulls(size) } } -} \ No newline at end of file +} diff --git a/service/src/main/java/com/github/kr328/clash/service/remote/IProfileManager.kt b/service/src/main/java/com/github/kr328/clash/service/remote/IProfileManager.kt index f5915f0f..0eace2ef 100644 --- a/service/src/main/java/com/github/kr328/clash/service/remote/IProfileManager.kt +++ b/service/src/main/java/com/github/kr328/clash/service/remote/IProfileManager.kt @@ -6,15 +6,15 @@ import java.util.* @BinderInterface interface IProfileManager { - suspend fun create(type: Profile.Type, name: String, source: String = ""): UUID + suspend fun create(type: Profile.Type, name: String, source: String = "", ageSecretKey: String? = null): UUID suspend fun clone(uuid: UUID): UUID suspend fun commit(uuid: UUID, callback: IFetchObserver? = null) suspend fun release(uuid: UUID) suspend fun delete(uuid: UUID) - suspend fun patch(uuid: UUID, name: String, source: String, interval: Long) + suspend fun patch(uuid: UUID, name: String, source: String, interval: Long, ageSecretKey: String?) suspend fun update(uuid: UUID) suspend fun queryByUUID(uuid: UUID): Profile? suspend fun queryAll(): List suspend fun queryActive(): Profile? suspend fun setActive(profile: Profile) -} \ No newline at end of file +}