From ffec64d209719ea65b033d3f48733ecf7622310f Mon Sep 17 00:00:00 2001 From: Viktor De Pasquale Date: Mon, 15 Apr 2019 18:36:38 +0200 Subject: [PATCH] Added safetynet to the rewritten home fragment --- .../magisk/model/events/ViewEvents.kt | 2 + .../topjohnwu/magisk/ui/home/HomeViewModel.kt | 59 ++++- .../magisk/ui/home/MagiskFragment.kt | 245 +++--------------- .../magisk/ui/home/SafetyNetState.kt | 5 + .../com/topjohnwu/magisk/view/SafetyNet.java | 86 +++--- app/src/main/res/layout/fragment_magisk.xml | 105 ++++---- 6 files changed, 202 insertions(+), 300 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/ui/home/SafetyNetState.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt b/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt index 10337cf65..bc92e7479 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/events/ViewEvents.kt @@ -13,3 +13,5 @@ class MagiskChangelogEvent : ViewEvent() class UninstallEvent : ViewEvent() class EnvFixEvent : ViewEvent() + +class UpdateSafetyNetEvent : ViewEvent() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt index 4eef9a973..c383dceec 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/HomeViewModel.kt @@ -8,6 +8,7 @@ import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.tasks.CheckUpdates import com.topjohnwu.magisk.ui.base.MagiskViewModel import com.topjohnwu.magisk.utils.Event +import com.topjohnwu.magisk.utils.ISafetyNetHelper import com.topjohnwu.magisk.utils.toggle import com.topjohnwu.net.Networking import com.topjohnwu.superuser.Shell @@ -66,6 +67,21 @@ class HomeViewModel( "" } + val safetyNetTitle = KObservableField(resources.getString(R.string.safetyNet_check_text)) + val ctsState = KObservableField(SafetyNetState.IDLE) + val basicIntegrityState = KObservableField(SafetyNetState.IDLE) + val safetyNetState = Observer(ctsState, basicIntegrityState) { + val cts = ctsState.value + val basic = basicIntegrityState.value + val states = listOf(cts, basic) + + when { + states.any { it == SafetyNetState.LOADING } -> State.LOADING + states.any { it == SafetyNetState.IDLE } -> State.LOADING + else -> State.LOADED + } + } + val hasRoot = KObservableField(false) private var shownDialog = false @@ -103,8 +119,46 @@ class HomeViewModel( MagiskItem.MAGISK -> MagiskChangelogEvent().publish() } + fun safetyNetPressed() { + ctsState.value = SafetyNetState.LOADING + basicIntegrityState.value = SafetyNetState.LOADING + safetyNetTitle.value = resources.getString(R.string.checking_safetyNet_status) + + UpdateSafetyNetEvent().publish() + } + + fun finishSafetyNetCheck(response: Int) = when { + response and 0x0F == 0 -> { + val hasCtsPassed = response and ISafetyNetHelper.CTS_PASS != 0 + val hasBasicIntegrityPassed = response and ISafetyNetHelper.BASIC_PASS != 0 + safetyNetTitle.value = resources.getString(R.string.safetyNet_check_success) + ctsState.value = if (hasCtsPassed) { + SafetyNetState.PASS + } else { + SafetyNetState.FAILED + } + basicIntegrityState.value = if (hasBasicIntegrityPassed) { + SafetyNetState.PASS + } else { + SafetyNetState.FAILED + } + } + response == -2 -> { + ctsState.value = SafetyNetState.IDLE + basicIntegrityState.value = SafetyNetState.IDLE + } + else -> { + ctsState.value = SafetyNetState.IDLE + basicIntegrityState.value = SafetyNetState.IDLE + val errorString = when (response) { + ISafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid + else -> R.string.safetyNet_api_error + } + safetyNetTitle.value = resources.getString(errorString) + } + } + fun refresh() { - shownDialog = false state = State.LOADING magiskState.value = MagiskState.LOADING managerState.value = MagiskState.LOADING @@ -155,7 +209,8 @@ class HomeViewModel( } private fun ensureEnv() { - val invalidStates = listOf(MagiskState.NOT_INSTALLED, MagiskState.NO_ROOT, MagiskState.LOADING) + val invalidStates = + listOf(MagiskState.NOT_INSTALLED, MagiskState.NO_ROOT, MagiskState.LOADING) // Don't bother checking env when magisk is not installed, loading or already has been shown if (invalidStates.any { it == magiskState.value } || shownDialog) return diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt index 0d7488fbf..2a262c488 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/MagiskFragment.kt @@ -3,56 +3,31 @@ package com.topjohnwu.magisk.ui.home import com.skoumal.teanity.viewevents.ViewEvent import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.databinding.FragmentMagiskBinding import com.topjohnwu.magisk.model.events.* +import com.topjohnwu.magisk.utils.ISafetyNetHelper import com.topjohnwu.magisk.view.MarkDownWindow +import com.topjohnwu.magisk.view.SafetyNet +import com.topjohnwu.magisk.view.SafetyNet.EXT_APK +import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog import com.topjohnwu.magisk.view.dialogs.EnvFixDialog import com.topjohnwu.magisk.view.dialogs.ManagerInstallDialog import com.topjohnwu.magisk.view.dialogs.UninstallDialog +import com.topjohnwu.net.Networking +import com.topjohnwu.superuser.Shell import org.koin.androidx.viewmodel.ext.android.viewModel import com.topjohnwu.magisk.ui.base.MagiskFragment as NewMagiskFragment -class MagiskFragment : NewMagiskFragment() { - - /*@BindView(R.id.swipeRefreshLayout) - internal var mSwipeRefreshLayout: SwipeRefreshLayout? = null - @BindView(R.id.linearLayout) - internal var root: LinearLayout? = null - - @BindView(R.id.install_option_card) - internal var installOptionCard: CardView? = null - @BindView(R.id.keep_force_enc) - internal var keepEncChkbox: CheckBox? = null - @BindView(R.id.keep_verity) - internal var keepVerityChkbox: CheckBox? = null - @BindView(R.id.install_option_expand) - internal var optionExpandLayout: ViewGroup? = null - @BindView(R.id.arrow) - internal var arrow: ImageView? = null - - @BindView(R.id.uninstall_button) - internal var uninstallButton: CardView? = null - - @BindColor(R.color.red500) - internal var colorBad: Int = 0 - @BindColor(R.color.green500) - internal var colorOK: Int = 0 - @BindColor(R.color.yellow500) - internal var colorWarn: Int = 0 - @BindColor(R.color.green500) - internal var colorNeutral: Int = 0 - @BindColor(R.color.blue500) - internal var colorInfo: Int = 0*/ - - /*private var magisk: UpdateCardHolder? = null - private var manager: UpdateCardHolder? = null - private var safetyNet: SafetyNet? = null - private var transition: Transition? = null - private var optionExpand: Expandable? = null*/ +class MagiskFragment : NewMagiskFragment(), + ISafetyNetHelper.Callback { override val layoutRes: Int = R.layout.fragment_magisk override val viewModel: HomeViewModel by viewModel() + override fun onResponse(responseCode: Int) = viewModel.finishSafetyNetCheck(responseCode) + override fun onEventDispatched(event: ViewEvent) { super.onEventDispatched(event) when (event) { @@ -62,6 +37,7 @@ class MagiskFragment : NewMagiskFragment uninstall() is ManagerChangelogEvent -> changelogManager() is EnvFixEvent -> fixEnv() + is UpdateSafetyNetEvent -> updateSafetyNet(false) } } @@ -82,184 +58,37 @@ class MagiskFragment : NewMagiskFragment download() } + .setNegativeButton(R.string.no_thanks) { _, _ -> viewModel.finishSafetyNetCheck(-2) } + .show() } - private fun updateCheckUI() { - /*var image: Int - var color: Int - var status: String - var button = "" - - - if (Config.remoteMagiskVersionCode < 0) { - color = colorNeutral - image = R.drawable.ic_help - status = getString(R.string.invalid_update_channel) - } else { - magisk!!.latestVersion.text = getString( - R.string.latest_version, - String.format( - Locale.US, "v%s (%d)", - Config.remoteMagiskVersionString, Config.remoteMagiskVersionCode - ) - ) - if (Config.remoteMagiskVersionCode > Config.magiskVersionCode) { - color = colorInfo - image = R.drawable.ic_update - status = getString(R.string.magisk_update_title) - button = getString(R.string.update) - } else { - color = colorOK - image = R.drawable.ic_check_circle - status = getString(R.string.magisk_up_to_date) - button = getString(R.string.install) + private fun updateSafetyNet(dieOnError: Boolean) { + try { + SafetyNet.dyRun(requireActivity(), this) + } catch (e: Exception) { + if (dieOnError) { + viewModel.finishSafetyNetCheck(-1) + return } + Shell.sh("rm -rf " + EXT_APK.parent).exec() + EXT_APK.parentFile?.mkdir() + downloadSafetyNet(!dieOnError) } - if (Config.magiskVersionCode > 0) { - // Only override status if Magisk is installed - magisk!!.statusIcon.setImageResource(image) - magisk!!.statusIcon.setColorFilter(color) - magisk!!.status.text = status - magisk!!.install.text = button - } - - if (Config.remoteManagerVersionCode < 0) { - color = colorNeutral - image = R.drawable.ic_help - status = getString(R.string.invalid_update_channel) - } else { - manager!!.latestVersion.text = getString( - R.string.latest_version, - String.format( - Locale.US, "v%s (%d)", - Config.remoteManagerVersionString, Config.remoteManagerVersionCode - ) - ) - if (Config.remoteManagerVersionCode > BuildConfig.VERSION_CODE) { - color = colorInfo - image = R.drawable.ic_update - status = getString(R.string.manager_update_title) - manager!!.install.setText(R.string.update) - } else { - color = colorOK - image = R.drawable.ic_check_circle - status = getString(R.string.manager_up_to_date) - manager!!.install.setText(R.string.install) - } - } - manager!!.statusIcon.setImageResource(image) - manager!!.statusIcon.setColorFilter(color) - manager!!.status.text = status - - magisk!!.setValid(Config.remoteMagiskVersionCode > 0) - manager!!.setValid(Config.remoteManagerVersionCode > 0) - - if (Config.remoteMagiskVersionCode < 0) { - // Hide install related components - installOptionCard!!.visibility = View.GONE - uninstallButton!!.visibility = View.GONE - } else { - // Show install related components - installOptionCard!!.visibility = View.VISIBLE - uninstallButton!!.visibility = if (Shell.rootAccess()) View.VISIBLE else View.GONE - } - - if (!shownDialog && Config.magiskVersionCode > 0 && - !Shell.su("env_check").exec().isSuccess - ) { - shownDialog = true - EnvFixDialog(requireActivity()).show() - }*/ - } - - companion object { - - private var shownDialog = false } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/home/SafetyNetState.kt b/app/src/main/java/com/topjohnwu/magisk/ui/home/SafetyNetState.kt new file mode 100644 index 000000000..fc0df345d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/ui/home/SafetyNetState.kt @@ -0,0 +1,5 @@ +package com.topjohnwu.magisk.ui.home + +enum class SafetyNetState { + LOADING, PASS, FAILED, IDLE +} \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java b/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java index e445439d1..67cbc36f4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java +++ b/app/src/main/java/com/topjohnwu/magisk/view/SafetyNet.java @@ -9,12 +9,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import androidx.annotation.StringRes; -import androidx.cardview.widget.CardView; -import butterknife.BindColor; -import butterknife.BindView; -import butterknife.OnClick; -import butterknife.Unbinder; + import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.R; @@ -22,13 +17,20 @@ import com.topjohnwu.magisk.utils.ISafetyNetHelper; import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog; import com.topjohnwu.net.Networking; import com.topjohnwu.superuser.Shell; -import dalvik.system.DexClassLoader; import java.io.File; +import androidx.annotation.StringRes; +import androidx.cardview.widget.CardView; +import butterknife.BindColor; +import butterknife.BindView; +import butterknife.OnClick; +import butterknife.Unbinder; +import dalvik.system.DexClassLoader; + public class SafetyNet implements ISafetyNetHelper.Callback { - private static final File EXT_APK = + public static final File EXT_APK = new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk"); /*@BindView(R.id.safetyNet_card) */ CardView safetyNetCard; @@ -45,7 +47,7 @@ public class SafetyNet implements ISafetyNetHelper.Callback { @BindColor(R.color.green500) int colorOK; public Unbinder unbinder; - private ExpandableViewHolder expandable; + private final ExpandableViewHolder expandable; public SafetyNet(View v) { unbinder = new SafetyNet_ViewBinding(this, v); @@ -55,27 +57,16 @@ public class SafetyNet implements ISafetyNetHelper.Callback { View.VISIBLE : View.GONE); } - @OnClick(R.id.safetyNet_refresh) - void safetyNet(View v) { - Runnable task = () -> { - safetyNetProgress.setVisibility(View.VISIBLE); - safetyNetRefreshIcon.setVisibility(View.INVISIBLE); - safetyNetStatusText.setText(R.string.checking_safetyNet_status); - check((Activity) v.getContext()); - expandable.collapse(); - }; - if (!SafetyNet.EXT_APK.exists()) { - // Show dialog - new CustomAlertDialog((Activity) v.getContext()) - .setTitle(R.string.proprietary_title) - .setMessage(R.string.proprietary_notice) - .setCancelable(true) - .setPositiveButton(R.string.yes, (d, i) -> task.run()) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } else { - task.run(); - } + public static void dyRun(Activity activity, Object callback) throws Exception { + DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(), + null, ISafetyNetHelper.class.getClassLoader()); + Class clazz = loader.loadClass("com.topjohnwu.snet.Snet"); + ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper", + Class.class, String.class, Activity.class, Object.class) + .invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, callback); + if (helper.getVersion() < Const.SNET_EXT_VER) + throw new Exception(); + helper.attest(); } public void reset() { @@ -117,27 +108,38 @@ public class SafetyNet implements ISafetyNetHelper.Callback { } } - private void dyRun(Activity activity) throws Exception { - DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(), - null, ISafetyNetHelper.class.getClassLoader()); - Class clazz = loader.loadClass("com.topjohnwu.snet.Snet"); - ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper", - Class.class, String.class, Activity.class, Object.class) - .invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, this); - if (helper.getVersion() < Const.SNET_EXT_VER) - throw new Exception(); - helper.attest(); + @OnClick(R.id.safetyNet_refresh) + void safetyNet(View v) { + Runnable task = () -> { + safetyNetProgress.setVisibility(View.VISIBLE); + safetyNetRefreshIcon.setVisibility(View.INVISIBLE); + safetyNetStatusText.setText(R.string.checking_safetyNet_status); + check((Activity) v.getContext()); + expandable.collapse(); + }; + if (!EXT_APK.exists()) { + // Show dialog + new CustomAlertDialog((Activity) v.getContext()) + .setTitle(R.string.proprietary_title) + .setMessage(R.string.proprietary_notice) + .setCancelable(true) + .setPositiveButton(R.string.yes, (d, i) -> task.run()) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } else { + task.run(); + } } private void check(Activity activity) { try { - dyRun(activity); + dyRun(activity, this); } catch (Exception ignored) { Shell.sh("rm -rf " + EXT_APK.getParent()).exec(); EXT_APK.getParentFile().mkdir(); Networking.get(Const.Url.SNET_URL).getAsFile(EXT_APK, f -> { try { - dyRun(activity); + dyRun(activity, this); } catch (Exception e) { e.printStackTrace(); onResponse(-1); diff --git a/app/src/main/res/layout/fragment_magisk.xml b/app/src/main/res/layout/fragment_magisk.xml index fb0f89a13..0fec41f48 100644 --- a/app/src/main/res/layout/fragment_magisk.xml +++ b/app/src/main/res/layout/fragment_magisk.xml @@ -1,13 +1,20 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + + + + + @@ -38,8 +45,8 @@ + android:layout_marginBottom="5dp" + android:layout_marginTop="5dp"> + android:paddingBottom="10dp" + android:paddingTop="10dp"> + android:layout_height="wrap_content" + android:paddingBottom="@dimen/margin_generic_half" + android:paddingTop="@dimen/margin_generic_half"> + + - - - - - - - + app:layout_constraintTop_toTopOf="@+id/cts_status" + tools:srcCompat="@drawable/ic_check_circle" /> - + app:layout_constraintTop_toTopOf="@+id/basic_status" + tools:srcCompat="@drawable/ic_check_circle" /> + app:layout_constraintTop_toTopOf="parent" + tools:text="ctsProfile: true" /> + app:layout_constraintTop_toBottomOf="@+id/cts_status" + tools:text="basicIntegrity: true" />