app: support config restrict policy

This commit is contained in:
vvb2060 2023-06-28 04:47:44 +08:00 committed by John Wu
parent ff18cb8e70
commit e5d36d1d24
12 changed files with 113 additions and 13 deletions

View File

@ -24,6 +24,7 @@ import androidx.core.widget.ImageViewCompat
import androidx.databinding.BindingAdapter import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener import androidx.databinding.InverseBindingListener
import androidx.databinding.InverseMethod
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager 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.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.slider.Slider
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.utils.TextHolder import com.topjohnwu.magisk.utils.TextHolder
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.widget.IndeterminateCheckBox import com.topjohnwu.widget.IndeterminateCheckBox
@ -306,3 +309,38 @@ fun TextView.setText(text: TextHolder) {
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) { fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
adapter = ArrayAdapter(context, layoutRes, items) 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
}
}

View File

@ -322,6 +322,12 @@ object Reauthenticate : BaseSettingsItem.Toggle() {
override var value by Config::suReAuth override var value by Config::suReAuth
override fun refresh() { 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
}

View File

@ -83,6 +83,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
// Can hide overlay windows on 12.0+ // Can hide overlay windows on 12.0+
list.remove(Tapjack) list.remove(Tapjack)
} }
if (Const.Version.isCanary()) {
list.add(Restrict)
}
} }
return list return list

View File

@ -4,11 +4,13 @@ import android.graphics.drawable.Drawable
import androidx.databinding.Bindable import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.model.su.SuPolicy import com.topjohnwu.magisk.core.model.su.SuPolicy
import com.topjohnwu.magisk.databinding.DiffItem import com.topjohnwu.magisk.databinding.DiffItem
import com.topjohnwu.magisk.databinding.ItemWrapper import com.topjohnwu.magisk.databinding.ItemWrapper
import com.topjohnwu.magisk.databinding.ObservableRvItem import com.topjohnwu.magisk.databinding.ObservableRvItem
import com.topjohnwu.magisk.databinding.set import com.topjohnwu.magisk.databinding.set
import com.topjohnwu.magisk.core.R as CoreR
class PolicyRvItem( class PolicyRvItem(
private val viewModel: SuperuserViewModel, private val viewModel: SuperuserViewModel,
@ -33,14 +35,34 @@ class PolicyRvItem(
var isExpanded = false var isExpanded = false
set(value) = set(value, field, { field = it }, BR.expanded) set(value) = set(value, field, { field = it }, BR.expanded)
val showSlider = Config.suRestrict || item.policy == SuPolicy.RESTRICT
@get:Bindable @get:Bindable
var isEnabled var isEnabled
get() = item.policy == SuPolicy.ALLOW get() = item.policy >= SuPolicy.ALLOW
set(value) = setImpl(value, isEnabled) { set(value) = setImpl(value, isEnabled) {
notifyPropertyChanged(BR.enabled) 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 @get:Bindable
var shouldNotify var shouldNotify
get() = item.notification get() = item.notification

View File

@ -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 } val items = itemsPolicies.filter { it.item.uid == item.item.uid }
fun updateState() { fun updateState() {
viewModelScope.launch { viewModelScope.launch {
val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny val res = if (policy >= SuPolicy.ALLOW) R.string.su_snack_grant else R.string.su_snack_deny
item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY item.item.policy = policy
db.update(item.item) db.update(item.item)
items.forEach { items.forEach {
it.notifyPropertyChanged(BR.enabled) it.notifyPropertyChanged(BR.enabled)
it.notifyPropertyChanged(BR.sliderValue)
} }
SnackbarEvent(res.asText(item.appName)).publish() SnackbarEvent(res.asText(item.appName)).publish()
} }

View File

@ -25,7 +25,7 @@
<include <include
android:id="@+id/log_track_container" android:id="@+id/log_track_container"
bullet="@{item.log.action == 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}" bullet="@{item.log.action >= 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
isBottom="@{item.isBottom}" isBottom="@{item.isBottom}"
isSelected="@{item.log.action != 2}" isSelected="@{item.log.action != 2}"
isTop="@{item.isTop}" isTop="@{item.isTop}"

View File

@ -5,6 +5,8 @@
<data> <data>
<import type="com.topjohnwu.magisk.databinding.DataBindingAdaptersKt" />
<variable <variable
name="item" name="item"
type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" /> type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" />
@ -85,16 +87,32 @@
app:layout_constraintVertical_bias="0" app:layout_constraintVertical_bias="0"
tools:text="com.topjohnwu.magisk" /> tools:text="com.topjohnwu.magisk" />
<com.google.android.material.switchmaterial.SwitchMaterial <FrameLayout
android:id="@+id/policy_indicator" android:id="@+id/policy_indicator"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/l1" android:layout_marginEnd="@dimen/l1"
android:checked="@={item.enabled}"
android:nextFocusLeft="@id/policy" android:nextFocusLeft="@id/policy"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.switchmaterial.SwitchMaterial
gone="@{item.showSlider}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="@={item.enabled}" />
<com.google.android.material.slider.Slider
goneUnless="@{item.showSlider}"
labelFormatter="@{item.sliderValueToPolicyString}"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:stepSize="1"
android:value="@={DataBindingAdaptersKt.policyToSliderValue(item.sliderValue)}"
android:valueFrom="1"
android:valueTo="3" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -32,6 +32,7 @@ object Config : PreferenceConfig, DBConfig {
const val SU_NOTIFICATION = "su_notification" const val SU_NOTIFICATION = "su_notification"
const val SU_REAUTH = "su_reauth" const val SU_REAUTH = "su_reauth"
const val SU_TAPJACK = "su_tapjack" const val SU_TAPJACK = "su_tapjack"
const val SU_RESTRICT = "su_restrict"
const val CHECK_UPDATES = "check_update" const val CHECK_UPDATES = "check_update"
const val RELEASE_CHANNEL = "release_channel" const val RELEASE_CHANNEL = "release_channel"
const val CUSTOM_CHANNEL = "custom_channel" const val CUSTOM_CHANNEL = "custom_channel"
@ -147,6 +148,7 @@ object Config : PreferenceConfig, DBConfig {
} }
var suReAuth by preference(Key.SU_REAUTH, false) var suReAuth by preference(Key.SU_REAUTH, false)
var suTapjack by preference(Key.SU_TAPJACK, true) 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 SU_FINGERPRINT = "su_fingerprint"
private const val UPDATE_CHANNEL = "update_channel" private const val UPDATE_CHANNEL = "update_channel"

View File

@ -70,7 +70,7 @@ object SuCallbackHandler {
}.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids) }.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids)
if (notify) if (notify)
notify(context, log.action == SuPolicy.ALLOW, log.appName) notify(context, log.action >= SuPolicy.ALLOW, log.appName)
runBlocking { ServiceLocator.logRepo.insert(log) } runBlocking { ServiceLocator.logRepo.insert(log) }
} }
@ -86,7 +86,7 @@ object SuCallbackHandler {
pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm) pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm)
}.getOrNull() ?: "[UID] $uid" }.getOrNull() ?: "[UID] $uid"
notify(context, policy == SuPolicy.ALLOW, appName) notify(context, policy >= SuPolicy.ALLOW, appName)
} }
private fun notify(context: Context, granted: Boolean, appName: String) { private fun notify(context: Context, granted: Boolean, appName: String) {

View File

@ -82,7 +82,11 @@ class SuRequestHandler(
} }
suspend fun respond(action: Int, time: Long) { 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) { if (time >= 0) {
policy.remain = TimeUnit.MINUTES.toSeconds(time) policy.remain = TimeUnit.MINUTES.toSeconds(time)
} else { } else {

View File

@ -54,6 +54,7 @@
<string name="touch_filtered_warning">由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应</string> <string name="touch_filtered_warning">由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应</string>
<string name="deny">拒绝</string> <string name="deny">拒绝</string>
<string name="prompt">提示</string> <string name="prompt">提示</string>
<string name="restrict">受限</string>
<string name="grant">允许</string> <string name="grant">允许</string>
<string name="su_warning">将授予对该设备的最高权限。\n如果不确定请拒绝</string> <string name="su_warning">将授予对该设备的最高权限。\n如果不确定请拒绝</string>
<string name="forever">永久</string> <string name="forever">永久</string>
@ -173,6 +174,8 @@
<string name="settings_su_auth_title">身份验证</string> <string name="settings_su_auth_title">身份验证</string>
<string name="settings_su_auth_summary">对超级用户请求验证身份</string> <string name="settings_su_auth_summary">对超级用户请求验证身份</string>
<string name="settings_su_auth_insecure">设备未配置验证方式</string> <string name="settings_su_auth_insecure">设备未配置验证方式</string>
<string name="settings_su_restrict_title">限制超级用户权能</string>
<string name="settings_su_restrict_summary">默认限制新的超级用户应用。警告,这会破坏大多数应用,不建议启用。</string>
<string name="settings_customization">个性化</string> <string name="settings_customization">个性化</string>
<string name="setting_add_shortcut_summary">在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面</string> <string name="setting_add_shortcut_summary">在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面</string>
<string name="settings_doh_title">安全 DNSDoH</string> <string name="settings_doh_title">安全 DNSDoH</string>

View File

@ -53,6 +53,7 @@
<string name="touch_filtered_warning">Because an app is obscuring a Superuser request, Magisk can\'t verify your response.</string> <string name="touch_filtered_warning">Because an app is obscuring a Superuser request, Magisk can\'t verify your response.</string>
<string name="deny">Deny</string> <string name="deny">Deny</string>
<string name="prompt">Prompt</string> <string name="prompt">Prompt</string>
<string name="restrict">Restrict</string>
<string name="grant">Grant</string> <string name="grant">Grant</string>
<string name="su_warning">Grants full access to your device.\nDeny if you\'re not sure!</string> <string name="su_warning">Grants full access to your device.\nDeny if you\'re not sure!</string>
<string name="forever">Forever</string> <string name="forever">Forever</string>
@ -170,6 +171,8 @@
<string name="settings_su_auth_title">User authentication</string> <string name="settings_su_auth_title">User authentication</string>
<string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string> <string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string>
<string name="settings_su_auth_insecure">No authentication method is configured on the device</string> <string name="settings_su_auth_insecure">No authentication method is configured on the device</string>
<string name="settings_su_restrict_title">Restrict root capabilities</string>
<string name="settings_su_restrict_summary">Will restrict new superuser apps by default. Warning, this will break most apps, do not enable it.</string>
<string name="settings_customization">Customization</string> <string name="settings_customization">Customization</string>
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string> <string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
<string name="settings_doh_title">DNS over HTTPS</string> <string name="settings_doh_title">DNS over HTTPS</string>