mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-04-22 10:51:32 +00:00
Do not go through a fragment for auth
This commit is contained in:
parent
678c07fff5
commit
e483d6befe
@ -156,7 +156,12 @@ object Config : PreferenceConfig, DBConfig {
|
|||||||
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB)
|
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB)
|
||||||
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)
|
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)
|
||||||
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
|
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
|
||||||
var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
|
private var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
|
||||||
|
var userAuth
|
||||||
|
get() = Info.isDeviceSecure && suBiometric
|
||||||
|
set(value) {
|
||||||
|
suBiometric = value
|
||||||
|
}
|
||||||
var zygisk by dbSettings(Key.ZYGISK, false)
|
var zygisk by dbSettings(Key.ZYGISK, false)
|
||||||
var denyList by BoolDBPropertyNoWrite(Key.DENYLIST, false)
|
var denyList by BoolDBPropertyNoWrite(Key.DENYLIST, false)
|
||||||
var suManager by dbStrings(Key.SU_MANAGER, "", true)
|
var suManager by dbStrings(Key.SU_MANAGER, "", true)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package com.topjohnwu.magisk.core
|
package com.topjohnwu.magisk.core
|
||||||
|
|
||||||
|
import android.app.KeyguardManager
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.topjohnwu.magisk.StubApk
|
import com.topjohnwu.magisk.StubApk
|
||||||
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.core.ktx.getProperty
|
import com.topjohnwu.magisk.core.ktx.getProperty
|
||||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||||
import com.topjohnwu.magisk.core.repository.NetworkService
|
import com.topjohnwu.magisk.core.repository.NetworkService
|
||||||
@ -46,6 +48,9 @@ object Info {
|
|||||||
|| Config.suMultiuserMode == Config.Value.MULTIUSER_MODE_USER)
|
|| Config.suMultiuserMode == Config.Value.MULTIUSER_MODE_USER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isDeviceSecure get() =
|
||||||
|
AppContext.getSystemService(KeyguardManager::class.java).isDeviceSecure
|
||||||
|
|
||||||
private fun loadState(): Env {
|
private fun loadState(): Env {
|
||||||
val v = fastCmd("magisk -v").split(":".toRegex())
|
val v = fastCmd("magisk -v").split(":".toRegex())
|
||||||
return Env(
|
return Env(
|
||||||
|
@ -20,6 +20,7 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.core.ktx.reflectField
|
import com.topjohnwu.magisk.core.ktx.reflectField
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
|
import com.topjohnwu.magisk.core.utils.RequestAuthentication
|
||||||
import com.topjohnwu.magisk.core.utils.RequestInstall
|
import com.topjohnwu.magisk.core.utils.RequestInstall
|
||||||
import com.topjohnwu.magisk.core.wrap
|
import com.topjohnwu.magisk.core.wrap
|
||||||
|
|
||||||
@ -43,6 +44,12 @@ abstract class BaseActivity : AppCompatActivity() {
|
|||||||
installCallback = null
|
installCallback = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var authenticateCallback: ((Boolean) -> Unit)? = null
|
||||||
|
val requestAuthenticate = registerForActivityResult(RequestAuthentication()) {
|
||||||
|
authenticateCallback?.invoke(it)
|
||||||
|
authenticateCallback = null
|
||||||
|
}
|
||||||
|
|
||||||
private var contentCallback: ContentResultCallback? = null
|
private var contentCallback: ContentResultCallback? = null
|
||||||
private val getContent = registerForActivityResult(GetContent()) {
|
private val getContent = registerForActivityResult(GetContent()) {
|
||||||
if (it != null) contentCallback?.onActivityResult(it)
|
if (it != null) contentCallback?.onActivityResult(it)
|
||||||
|
@ -12,7 +12,6 @@ import com.topjohnwu.magisk.core.data.magiskdb.StringDao
|
|||||||
import com.topjohnwu.magisk.core.ktx.deviceProtectedContext
|
import com.topjohnwu.magisk.core.ktx.deviceProtectedContext
|
||||||
import com.topjohnwu.magisk.core.repository.LogRepository
|
import com.topjohnwu.magisk.core.repository.LogRepository
|
||||||
import com.topjohnwu.magisk.core.repository.NetworkService
|
import com.topjohnwu.magisk.core.repository.NetworkService
|
||||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.utils.NoCopySpannableFactory
|
import io.noties.markwon.utils.NoCopySpannableFactory
|
||||||
|
|
||||||
@ -24,7 +23,6 @@ object ServiceLocator {
|
|||||||
lateinit var context: Context
|
lateinit var context: Context
|
||||||
val deContext by lazy { context.deviceProtectedContext }
|
val deContext by lazy { context.deviceProtectedContext }
|
||||||
val timeoutPrefs by lazy { deContext.getSharedPreferences("su_timeout", 0) }
|
val timeoutPrefs by lazy { deContext.getSharedPreferences("su_timeout", 0) }
|
||||||
val biometrics by lazy { BiometricHelper(context) }
|
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
val policyDB = PolicyDao()
|
val policyDB = PolicyDao()
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.core.utils
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.KeyguardManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import com.topjohnwu.magisk.core.Config
|
|
||||||
|
|
||||||
class BiometricHelper(context: Context) {
|
|
||||||
|
|
||||||
private val mgr = context.getSystemService(KeyguardManager::class.java)
|
|
||||||
|
|
||||||
val isSupported get() = mgr.isDeviceSecure
|
|
||||||
|
|
||||||
val isEnabled get() = isSupported && Config.suBiometric
|
|
||||||
|
|
||||||
fun authenticate(
|
|
||||||
activity: FragmentActivity,
|
|
||||||
onError: () -> Unit = {},
|
|
||||||
onSuccess: () -> Unit) {
|
|
||||||
val tag = BiometricFragment::class.java.name
|
|
||||||
val intent = mgr.createConfirmDeviceCredentialIntent(null, null)
|
|
||||||
val fragmentManager = activity.supportFragmentManager
|
|
||||||
var fragment = fragmentManager.findFragmentByTag(tag) as BiometricFragment?
|
|
||||||
if (fragment == null) {
|
|
||||||
fragment = BiometricFragment()
|
|
||||||
fragmentManager.beginTransaction()
|
|
||||||
.add(0, fragment, tag)
|
|
||||||
.commitNow()
|
|
||||||
}
|
|
||||||
fragment.start(intent, onError, onSuccess)
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiometricFragment : Fragment() {
|
|
||||||
private val code = 1
|
|
||||||
private var onError: () -> Unit = {}
|
|
||||||
private var onSuccess: () -> Unit = {}
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == code) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
onSuccess()
|
|
||||||
} else {
|
|
||||||
onError()
|
|
||||||
}
|
|
||||||
onError = {}
|
|
||||||
onSuccess = {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start(intent: Intent, onError: () -> Unit, onSuccess: () -> Unit) {
|
|
||||||
this.onError = onError
|
|
||||||
this.onSuccess = onSuccess
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
|
|
||||||
startActivityForResult(intent, code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.topjohnwu.magisk.core.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.KeyguardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
|
|
||||||
|
class RequestAuthentication: ActivityResultContract<Unit, Boolean>() {
|
||||||
|
|
||||||
|
override fun createIntent(context: Context, input: Unit) =
|
||||||
|
context.getSystemService(KeyguardManager::class.java)
|
||||||
|
.createConfirmDeviceCredentialIntent(null, null)
|
||||||
|
|
||||||
|
override fun parseResult(resultCode: Int, intent: Intent?) =
|
||||||
|
resultCode == Activity.RESULT_OK
|
||||||
|
}
|
@ -1,38 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.events
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.arch.ActivityExecutor
|
|
||||||
import com.topjohnwu.magisk.arch.UIActivity
|
|
||||||
import com.topjohnwu.magisk.arch.ViewEvent
|
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
|
|
||||||
class BiometricEvent(
|
|
||||||
builder: Builder.() -> Unit
|
|
||||||
) : ViewEvent(), ActivityExecutor {
|
|
||||||
|
|
||||||
private var listenerOnFailure: () -> Unit = {}
|
|
||||||
private var listenerOnSuccess: () -> Unit = {}
|
|
||||||
|
|
||||||
init {
|
|
||||||
builder(Builder())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invoke(activity: UIActivity<*>) {
|
|
||||||
ServiceLocator.biometrics.authenticate(
|
|
||||||
activity,
|
|
||||||
onError = listenerOnFailure,
|
|
||||||
onSuccess = listenerOnSuccess
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class Builder internal constructor() {
|
|
||||||
|
|
||||||
fun onFailure(listener: () -> Unit) {
|
|
||||||
listenerOnFailure = listener
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSuccess(listener: () -> Unit) {
|
|
||||||
listenerOnSuccess = listener
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -51,6 +51,16 @@ class RecreateEvent : ViewEvent(), ActivityExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BiometricEvent(
|
||||||
|
private val callback: () -> Unit
|
||||||
|
) : ViewEvent(), ActivityExecutor {
|
||||||
|
|
||||||
|
override fun invoke(activity: UIActivity<*>) {
|
||||||
|
activity.authenticateCallback = { if (it) callback() }
|
||||||
|
activity.requestAuthenticate.launch(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class GetContentEvent(
|
class GetContentEvent(
|
||||||
private val type: String,
|
private val type: String,
|
||||||
private val callback: ContentResultCallback
|
private val callback: ContentResultCallback
|
||||||
|
@ -12,7 +12,6 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.activity
|
import com.topjohnwu.magisk.core.ktx.activity
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||||
@ -286,14 +285,10 @@ object Tapjack : BaseSettingsItem.Toggle() {
|
|||||||
object Biometrics : BaseSettingsItem.Toggle() {
|
object Biometrics : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_su_biometric_title.asText()
|
override val title = R.string.settings_su_biometric_title.asText()
|
||||||
override var description = R.string.settings_su_biometric_summary.asText()
|
override var description = R.string.settings_su_biometric_summary.asText()
|
||||||
override var value
|
override var value by Config::userAuth
|
||||||
get() = ServiceLocator.biometrics.isEnabled
|
|
||||||
set(value) {
|
|
||||||
Config.suBiometric = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun refresh() {
|
override fun refresh() {
|
||||||
isEnabled = ServiceLocator.biometrics.isSupported
|
isEnabled = Info.isDeviceSecure
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
description = R.string.no_biometric.asText()
|
description = R.string.no_biometric.asText()
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
when (item) {
|
when (item) {
|
||||||
DownloadPath -> withExternalRW(andThen)
|
DownloadPath -> withExternalRW(andThen)
|
||||||
UpdateChecker -> withPostNotificationPermission(andThen)
|
UpdateChecker -> withPostNotificationPermission(andThen)
|
||||||
Biometrics -> authenticate(andThen)
|
Biometrics -> BiometricEvent(andThen).publish()
|
||||||
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
||||||
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
||||||
SystemlessHosts -> createHosts()
|
SystemlessHosts -> createHosts()
|
||||||
@ -119,13 +119,6 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun authenticate(callback: () -> Unit) {
|
|
||||||
BiometricEvent {
|
|
||||||
// allow the change on success
|
|
||||||
onSuccess { callback() }
|
|
||||||
}.publish()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createHosts() {
|
private fun createHosts() {
|
||||||
Shell.cmd("add_hosts_module").submit {
|
Shell.cmd("add_hosts_module").submit {
|
||||||
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
||||||
|
@ -10,14 +10,18 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||||
import com.topjohnwu.magisk.databinding.*
|
import com.topjohnwu.magisk.databinding.MergeObservableList
|
||||||
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
|
import com.topjohnwu.magisk.databinding.diffList
|
||||||
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.dialog.SuperuserRevokeDialog
|
import com.topjohnwu.magisk.dialog.SuperuserRevokeDialog
|
||||||
import com.topjohnwu.magisk.events.BiometricEvent
|
import com.topjohnwu.magisk.events.BiometricEvent
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
@ -113,10 +117,8 @@ class SuperuserViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.userAuth) {
|
||||||
BiometricEvent {
|
BiometricEvent { updateState() }.publish()
|
||||||
onSuccess { updateState() }
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
SuperuserRevokeDialog(item.title) { updateState() }.show()
|
SuperuserRevokeDialog(item.title) { updateState() }.show()
|
||||||
}
|
}
|
||||||
@ -168,10 +170,8 @@ class SuperuserViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.userAuth) {
|
||||||
BiometricEvent {
|
BiometricEvent { updateState() }.publish()
|
||||||
onSuccess { updateState() }
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
updateState()
|
updateState()
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import com.topjohnwu.magisk.arch.BaseViewModel
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
|
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
|
||||||
@ -77,12 +76,8 @@ class SuRequestViewModel(
|
|||||||
|
|
||||||
fun grantPressed() {
|
fun grantPressed() {
|
||||||
cancelTimer()
|
cancelTimer()
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.userAuth) {
|
||||||
BiometricEvent {
|
BiometricEvent { respond(ALLOW) }.publish()
|
||||||
onSuccess {
|
|
||||||
respond(ALLOW)
|
|
||||||
}
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
respond(ALLOW)
|
respond(ALLOW)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user