Replace package names on UIDs in custom config#5527
Replace package names on UIDs in custom config#5527fanymagnet wants to merge 1 commit into2dust:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Updates custom-config handling so that, when TUN/VPN mode is enabled, routing rules can convert app package names to UIDs and the config can be auto-augmented with a tun inbound when missing.
Changes:
- Parse custom config JSON and rewrite
routing.rules[*].processfrom package names to UID strings. - Detect whether a
tuninbound exists (now byprotocol == "tun") and inject the templatetuninbound if absent. - Refactor JSON traversal to use safer
takeIf { isJson* }checks.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| val packages = process.mapNotNull { | ||
| it.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }?.asString | ||
| }.takeIf { it.isNotEmpty() } ?: continue | ||
| val uids = PackageUidResolver.packageNamesToUids(context, packages).takeIf { it.isNotEmpty() } ?: continue | ||
|
|
||
| rule.add("process", JsonArray().apply { uids.forEach { add(it) } }) |
There was a problem hiding this comment.
The conversion overwrites process with only the successfully-resolved package UIDs. If the original array contains numeric UID strings, or package names that fail to resolve, those entries are silently dropped, changing routing behavior. Prefer converting element-by-element (e.g., keep numeric UID strings as-is; replace only resolvable package names; preserve unresolved values).
| val packages = process.mapNotNull { | |
| it.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }?.asString | |
| }.takeIf { it.isNotEmpty() } ?: continue | |
| val uids = PackageUidResolver.packageNamesToUids(context, packages).takeIf { it.isNotEmpty() } ?: continue | |
| rule.add("process", JsonArray().apply { uids.forEach { add(it) } }) | |
| val resolvedProcess = JsonArray() | |
| for (processElem in process) { | |
| val processName = processElem | |
| .takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString } | |
| ?.asString | |
| if (processName == null) { | |
| resolvedProcess.add(processElem) | |
| continue | |
| } | |
| if (processName.toIntOrNull() != null) { | |
| resolvedProcess.add(processName) | |
| continue | |
| } | |
| val uid = PackageUidResolver.packageNamesToUids(context, listOf(processName)).firstOrNull() | |
| resolvedProcess.add(uid ?: processName) | |
| } | |
| rule.add("process", resolvedProcess) |
| json.getAsJsonArray("inbounds") | ||
| } else { | ||
| JsonArray() | ||
| // check if package names need to replaced on UIDs |
There was a problem hiding this comment.
Grammar: "need to replaced on UIDs" is incorrect; consider rephrasing to "need to be replaced with UIDs" (or similar).
| // check if package names need to replaced on UIDs | |
| // Check whether package names need to be replaced with UIDs |
| for (elem in rulesJson) { | ||
| val rule = elem.takeIf { it.isJsonObject }?.asJsonObject ?: continue | ||
| val process = rule.get("process")?.takeIf { it.isJsonArray }?.asJsonArray ?: continue | ||
| val packages = process.mapNotNull { | ||
| it.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }?.asString | ||
| }.takeIf { it.isNotEmpty() } ?: continue | ||
| val uids = PackageUidResolver.packageNamesToUids(context, packages).takeIf { it.isNotEmpty() } ?: continue | ||
|
|
||
| rule.add("process", JsonArray().apply { uids.forEach { add(it) } }) |
There was a problem hiding this comment.
process replacement runs for every custom config when needTun() is true, but UID-based process routing is only supported when SettingsManager.canUseProcessRouting() is true (see getRoutingUserRule). Consider guarding this conversion (or leaving process untouched) when process routing isn’t available to avoid changing custom configs’ semantics on unsupported devices/settings.
| for (elem in rulesJson) { | |
| val rule = elem.takeIf { it.isJsonObject }?.asJsonObject ?: continue | |
| val process = rule.get("process")?.takeIf { it.isJsonArray }?.asJsonArray ?: continue | |
| val packages = process.mapNotNull { | |
| it.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }?.asString | |
| }.takeIf { it.isNotEmpty() } ?: continue | |
| val uids = PackageUidResolver.packageNamesToUids(context, packages).takeIf { it.isNotEmpty() } ?: continue | |
| rule.add("process", JsonArray().apply { uids.forEach { add(it) } }) | |
| if (SettingsManager.canUseProcessRouting()) { | |
| for (elem in rulesJson) { | |
| val rule = elem.takeIf { it.isJsonObject }?.asJsonObject ?: continue | |
| val process = rule.get("process")?.takeIf { it.isJsonArray }?.asJsonArray ?: continue | |
| val packages = process.mapNotNull { | |
| it.takeIf { it.isJsonPrimitive && it.asJsonPrimitive.isString }?.asString | |
| }.takeIf { it.isNotEmpty() } ?: continue | |
| val uids = PackageUidResolver.packageNamesToUids(context, packages).takeIf { it.isNotEmpty() } ?: continue | |
| rule.add("process", JsonArray().apply { uids.forEach { add(it) } }) | |
| } |
No description provided.