From e5d36d1d24b418f374c263aae1a5d48ab398f129 Mon Sep 17 00:00:00 2001 From: vvb2060 Date: Wed, 28 Jun 2023 04:47:44 +0800 Subject: [PATCH] app: support config restrict policy --- .../magisk/databinding/DataBindingAdapters.kt | 38 +++++++++++++++++++ .../magisk/ui/settings/SettingsItems.kt | 8 +++- .../magisk/ui/settings/SettingsViewModel.kt | 3 ++ .../magisk/ui/superuser/PolicyRvItem.kt | 26 ++++++++++++- .../magisk/ui/superuser/SuperuserViewModel.kt | 7 ++-- .../main/res/layout/item_log_access_md2.xml | 2 +- .../src/main/res/layout/item_policy_md2.xml | 24 ++++++++++-- .../java/com/topjohnwu/magisk/core/Config.kt | 2 + .../magisk/core/su/SuCallbackHandler.kt | 4 +- .../magisk/core/su/SuRequestHandler.kt | 6 ++- .../src/main/res/values-zh-rCN/strings.xml | 3 ++ app/core/src/main/res/values/strings.xml | 3 ++ 12 files changed, 113 insertions(+), 13 deletions(-) diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt b/app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt index 6cb54a722..9cc6084d9 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt @@ -24,6 +24,7 @@ import androidx.core.widget.ImageViewCompat import androidx.databinding.BindingAdapter import androidx.databinding.InverseBindingAdapter import androidx.databinding.InverseBindingListener +import androidx.databinding.InverseMethod import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.GridLayoutManager @@ -33,9 +34,11 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView import com.google.android.material.chip.Chip +import com.google.android.material.slider.Slider import com.google.android.material.textfield.TextInputLayout import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.di.ServiceLocator +import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.utils.TextHolder import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.widget.IndeterminateCheckBox @@ -306,3 +309,38 @@ fun TextView.setText(text: TextHolder) { fun Spinner.setAdapter(items: Array, layoutRes: Int) { adapter = ArrayAdapter(context, layoutRes, items) } + +@BindingAdapter("labelFormatter") +fun Slider.setLabelFormatter(formatter: (Float) -> Int) { + setLabelFormatter { value -> resources.getString(formatter(value)) } +} + +@InverseBindingAdapter(attribute = "android:value") +fun Slider.getValueBinding() = value + +@BindingAdapter("android:valueAttrChanged") +fun Slider.setListener(attrChange: InverseBindingListener) { + addOnSliderTouchListener(object : Slider.OnSliderTouchListener { + override fun onStartTrackingTouch(slider: Slider) = Unit + override fun onStopTrackingTouch(slider: Slider) = attrChange.onChange() + }) +} + +@InverseMethod("sliderValueToPolicy") +fun policyToSliderValue(policy: Int): Float { + return when (policy) { + SuPolicy.DENY -> 1f + SuPolicy.RESTRICT -> 2f + SuPolicy.ALLOW -> 3f + else -> 1f + } +} + +fun sliderValueToPolicy(value: Float): Int { + return when (value) { + 1f -> SuPolicy.DENY + 2f -> SuPolicy.RESTRICT + 3f -> SuPolicy.ALLOW + else -> SuPolicy.DENY + } +} diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index ea6f00eab..2bb886411 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -322,6 +322,12 @@ object Reauthenticate : BaseSettingsItem.Toggle() { override var value by Config::suReAuth override fun refresh() { - isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Info.showSuperUser + isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O } } + +object Restrict : BaseSettingsItem.Toggle() { + override val title = CoreR.string.settings_su_restrict_title.asText() + override val description = CoreR.string.settings_su_restrict_summary.asText() + override var value by Config::suRestrict +} diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt index 234c38923..3a2ac5140 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt @@ -83,6 +83,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler { // Can hide overlay windows on 12.0+ list.remove(Tapjack) } + if (Const.Version.isCanary()) { + list.add(Restrict) + } } return list diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt index 816b63a52..ab34aa4b9 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/PolicyRvItem.kt @@ -4,11 +4,13 @@ import android.graphics.drawable.Drawable import androidx.databinding.Bindable import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.databinding.DiffItem import com.topjohnwu.magisk.databinding.ItemWrapper import com.topjohnwu.magisk.databinding.ObservableRvItem import com.topjohnwu.magisk.databinding.set +import com.topjohnwu.magisk.core.R as CoreR class PolicyRvItem( private val viewModel: SuperuserViewModel, @@ -33,14 +35,34 @@ class PolicyRvItem( var isExpanded = false set(value) = set(value, field, { field = it }, BR.expanded) + val showSlider = Config.suRestrict || item.policy == SuPolicy.RESTRICT + @get:Bindable var isEnabled - get() = item.policy == SuPolicy.ALLOW + get() = item.policy >= SuPolicy.ALLOW set(value) = setImpl(value, isEnabled) { notifyPropertyChanged(BR.enabled) - viewModel.togglePolicy(this, value) + viewModel.updatePolicy(this, if (it) SuPolicy.ALLOW else SuPolicy.DENY) } + @get:Bindable + var sliderValue + get() = item.policy + set(value) = setImpl(value, sliderValue) { + notifyPropertyChanged(BR.sliderValue) + notifyPropertyChanged(BR.enabled) + viewModel.updatePolicy(this, it) + } + + val sliderValueToPolicyString: (Float) -> Int = { value -> + when (value.toInt()) { + 1 -> CoreR.string.deny + 2 -> CoreR.string.restrict + 3 -> CoreR.string.grant + else -> CoreR.string.deny + } + } + @get:Bindable var shouldNotify get() = item.notification diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt index 6af21a5a2..3922c92bc 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/superuser/SuperuserViewModel.kt @@ -156,15 +156,16 @@ class SuperuserViewModel( } } - fun togglePolicy(item: PolicyRvItem, enable: Boolean) { + fun updatePolicy(item: PolicyRvItem, policy: Int) { val items = itemsPolicies.filter { it.item.uid == item.item.uid } fun updateState() { viewModelScope.launch { - val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny - item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY + val res = if (policy >= SuPolicy.ALLOW) R.string.su_snack_grant else R.string.su_snack_deny + item.item.policy = policy db.update(item.item) items.forEach { it.notifyPropertyChanged(BR.enabled) + it.notifyPropertyChanged(BR.sliderValue) } SnackbarEvent(res.asText(item.appName)).publish() } diff --git a/app/apk/src/main/res/layout/item_log_access_md2.xml b/app/apk/src/main/res/layout/item_log_access_md2.xml index 146d74177..6aaaaf19b 100644 --- a/app/apk/src/main/res/layout/item_log_access_md2.xml +++ b/app/apk/src/main/res/layout/item_log_access_md2.xml @@ -25,7 +25,7 @@ + + @@ -85,16 +87,32 @@ app:layout_constraintVertical_bias="0" tools:text="com.topjohnwu.magisk" /> - + app:layout_constraintTop_toTopOf="parent"> + + + + + diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt index ca911597b..7fd4f8598 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt @@ -32,6 +32,7 @@ object Config : PreferenceConfig, DBConfig { const val SU_NOTIFICATION = "su_notification" const val SU_REAUTH = "su_reauth" const val SU_TAPJACK = "su_tapjack" + const val SU_RESTRICT = "su_restrict" const val CHECK_UPDATES = "check_update" const val RELEASE_CHANNEL = "release_channel" const val CUSTOM_CHANNEL = "custom_channel" @@ -147,6 +148,7 @@ object Config : PreferenceConfig, DBConfig { } var suReAuth by preference(Key.SU_REAUTH, false) var suTapjack by preference(Key.SU_TAPJACK, true) + var suRestrict by preference(Key.SU_RESTRICT, false) private const val SU_FINGERPRINT = "su_fingerprint" private const val UPDATE_CHANNEL = "update_channel" diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt index 65f278e08..7c0d53172 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuCallbackHandler.kt @@ -70,7 +70,7 @@ object SuCallbackHandler { }.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids) if (notify) - notify(context, log.action == SuPolicy.ALLOW, log.appName) + notify(context, log.action >= SuPolicy.ALLOW, log.appName) runBlocking { ServiceLocator.logRepo.insert(log) } } @@ -86,7 +86,7 @@ object SuCallbackHandler { pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm) }.getOrNull() ?: "[UID] $uid" - notify(context, policy == SuPolicy.ALLOW, appName) + notify(context, policy >= SuPolicy.ALLOW, appName) } private fun notify(context: Context, granted: Boolean, appName: String) { diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt index e10f8cccd..a624c01ce 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/su/SuRequestHandler.kt @@ -82,7 +82,11 @@ class SuRequestHandler( } suspend fun respond(action: Int, time: Long) { - policy.policy = action + if (action == SuPolicy.ALLOW && Config.suRestrict) { + policy.policy = SuPolicy.RESTRICT + } else { + policy.policy = action + } if (time >= 0) { policy.remain = TimeUnit.MINUTES.toSeconds(time) } else { diff --git a/app/core/src/main/res/values-zh-rCN/strings.xml b/app/core/src/main/res/values-zh-rCN/strings.xml index cd093833a..eee017f27 100644 --- a/app/core/src/main/res/values-zh-rCN/strings.xml +++ b/app/core/src/main/res/values-zh-rCN/strings.xml @@ -54,6 +54,7 @@ 由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应 拒绝 提示 + 受限 允许 将授予对该设备的最高权限。\n如果不确定,请拒绝! 永久 @@ -173,6 +174,8 @@ 身份验证 对超级用户请求验证身份 设备未配置验证方式 + 限制超级用户权能 + 默认限制新的超级用户应用。警告,这会破坏大多数应用,不建议启用。 个性化 在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面 安全 DNS(DoH) diff --git a/app/core/src/main/res/values/strings.xml b/app/core/src/main/res/values/strings.xml index 41b3c384d..261a40a69 100644 --- a/app/core/src/main/res/values/strings.xml +++ b/app/core/src/main/res/values/strings.xml @@ -53,6 +53,7 @@ Because an app is obscuring a Superuser request, Magisk can\'t verify your response. Deny Prompt + Restrict Grant Grants full access to your device.\nDeny if you\'re not sure! Forever @@ -170,6 +171,8 @@ User authentication Ask for user authentication during Superuser requests No authentication method is configured on the device + Restrict root capabilities + Will restrict new superuser apps by default. Warning, this will break most apps, do not enable it. Customization Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app DNS over HTTPS