Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 8c9aacee authored by iTrooz's avatar iTrooz Committed by Marvin W.
Browse files

SafetyNet: Store and display recent requests

parent ec7397c3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import androidx.navigation.NavController
import androidx.navigation.navOptions
import androidx.navigation.ui.R

fun ByteArray.toHexString() : String = joinToString("") { "%02x".format(it) }

fun PackageManager.getApplicationInfoIfExists(packageName: String?, flags: Int = 0): ApplicationInfo? = packageName?.let {
    try {
        getApplicationInfo(it, flags)
+7 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ import android.os.Handler
import android.os.Looper
import android.util.Base64
import android.util.Log
import androidx.navigation.fragment.findNavController
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
@@ -27,6 +28,7 @@ import kotlin.random.Random
class SafetyNetPreferencesFragment : PreferenceFragmentCompat() {
    private lateinit var runAttest: Preference
    private lateinit var runReCaptcha: Preference
    private lateinit var seeRecent: Preference

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.preferences_safetynet)
@@ -36,6 +38,7 @@ class SafetyNetPreferencesFragment : PreferenceFragmentCompat() {
    override fun onBindPreferences() {
        runAttest = preferenceScreen.findPreference("pref_snet_run_attest") ?: runAttest
        runReCaptcha = preferenceScreen.findPreference("pref_recaptcha_run_test") ?: runReCaptcha
        seeRecent = preferenceScreen.findPreference("pref_snet_recent") ?: seeRecent

        // TODO: Use SafetyNet client library once ready
        runAttest.setOnPreferenceClickListener {
@@ -124,5 +127,9 @@ class SafetyNetPreferencesFragment : PreferenceFragmentCompat() {
            }
            true
        }
        seeRecent.setOnPreferenceClickListener {
            findNavController().navigate(requireContext(), R.id.openSafetyNetRecentList)
            true
        }
    }
}
+94 −0
Original line number Diff line number Diff line
package org.microg.gms.ui

import android.annotation.SuppressLint
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.text.format.DateUtils
import android.widget.Toast
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.google.android.gms.R
import org.json.JSONException
import org.json.JSONObject
import org.microg.gms.firebase.auth.getStringOrNull
import org.microg.gms.safetynet.SafetyNetSummary


class SafetyNetRecentAttestationPreferencesFragment : PreferenceFragmentCompat() {

    lateinit var snetSummary: SafetyNetSummary

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        addPreferencesFromResource(R.xml.preferences_snet_recent_attestation)
        snetSummary = arguments?.get("summary") as SafetyNetSummary
    }

    @SuppressLint("RestrictedApi")
    override fun onBindPreferences() {
        val requestType: Preference = preferenceScreen.findPreference("pref_request_type")!!
        val time : Preference = preferenceScreen.findPreference("pref_time")!!
        val nonce : Preference = preferenceScreen.findPreference("pref_nonce")!!
        val status : Preference = preferenceScreen.findPreference("pref_status")!!
        val evalType : Preference = preferenceScreen.findPreference("pref_eval_type")!!
        val advice : Preference = preferenceScreen.findPreference("pref_advice")!!
        val copyResult : Preference = preferenceScreen.findPreference("pref_copy_result")!!

        requestType.summary = "ATTESTATION"

        time.summary = DateUtils.getRelativeDateTimeString(context, snetSummary.timestamp, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)


        snetSummary.nonce?.toHexString().let {
            if (it == null) {
                nonce.summary = "None"
            } else {
                nonce.summary = it
            }
        }

        if(snetSummary.responseStatus==null){
            status.summary = "Not completed yet"
        }else if(snetSummary.responseStatus!!.isSuccess) {
            try {
                val json = JSONObject(snetSummary.responseData!!)
                evalType.summary = json.getString("evaluationType")
                advice.summary = json.getStringOrNull("advice") ?: "None"

                val basicIntegrity = json.getBoolean("basicIntegrity")
                val ctsProfileMatch = json.getBoolean("ctsProfileMatch")

                status.summary = when{
                    basicIntegrity && ctsProfileMatch -> {
                        "Integrity and CTS passed"
                    }
                    basicIntegrity -> {
                        "CTS failed"
                    }
                    else -> {
                        "Integrity failed"
                    }
                }

            } catch (e: JSONException) {
                e.printStackTrace()
                status.summary = "Invalid JSON"
            }
        }else{
            status.summary = snetSummary.responseStatus!!.statusMessage
        }

        copyResult.setOnPreferenceClickListener {
            val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
            val clip = ClipData.newPlainText("JSON JWS data", snetSummary.responseData)
            clipboard.setPrimaryClip(clip)

            Toast.makeText(context, "Copied to clipboard !", Toast.LENGTH_SHORT).show()

            true
        }

    }

}
 No newline at end of file
+61 −0
Original line number Diff line number Diff line
package org.microg.gms.ui

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ListView
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.add
import androidx.fragment.app.commit
import com.google.android.gms.R
import com.google.android.gms.databinding.SafetyNetRecentFragmentBinding
import org.microg.gms.safetynet.SafetyNetRequestType
import org.microg.gms.safetynet.SafetyNetSummary

class SafetyNetRecentFragment : Fragment(R.layout.safety_net_recent_fragment) {


    class MyListView(context: Context) : ListView(context) {

    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = SafetyNetRecentFragmentBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val summary = arguments?.get("summary") as SafetyNetSummary

        if(savedInstanceState==null){
            parentFragmentManager.commit {
                setReorderingAllowed(true)
                if(summary.requestType==SafetyNetRequestType.ATTESTATION){
                    add<SafetyNetRecentAttestationPreferencesFragment>(R.id.sub_preferences, args=arguments)
                }else{
                    add<SafetyNetRecentRecaptchaPreferencesFragment>(R.id.sub_preferences, args=arguments)
                }
            }
        }



        val pm = requireContext().packageManager
        val appInfo = pm.getApplicationInfoIfExists(summary.packageName)
        if(appInfo==null) return Toast.makeText(context, "Application not installed", Toast.LENGTH_SHORT).show()


        binding.appIcon.setImageDrawable(appInfo.loadIcon(pm))
        binding.appName.text = appInfo.loadLabel(pm)
        binding.packageName.text = summary.packageName

    }

    lateinit var binding: SafetyNetRecentFragmentBinding

}
+65 −0
Original line number Diff line number Diff line
package org.microg.gms.ui

import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.R
import org.microg.gms.safetynet.SafetyNetDatabase

class SafetyNetRecentListFragment : Fragment(R.layout.safety_net_recents_list_fragment){

    private lateinit var adapter: SafetyNetSummaryAdapter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setHasOptionsMenu(true)

        val db = SafetyNetDatabase(requireContext())
        val recentRequests = db.recentRequests
        db.close()

        val recyclerView: RecyclerView = view.findViewById(R.id.snet_recent_recyclerview)
        if(recentRequests.isEmpty()){
            recyclerView.isVisible = false
        }else{
            recyclerView.layoutManager = LinearLayoutManager(context)
            adapter = SafetyNetSummaryAdapter(recentRequests) {
                findNavController().navigate(requireContext(), R.id.openSafetyNetRecent, bundleOf(
                    "summary" to it
                ))
            }
            recyclerView.adapter = adapter
        }
    }


    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        menu.add(0, MENU_CLEAR_REQUESTS, 0, R.string.menu_clear_recent_requests)
        super.onCreateOptionsMenu(menu, inflater)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            MENU_CLEAR_REQUESTS -> {
                val db = SafetyNetDatabase(requireContext())
                db.clearAllRequests()
                db.close()
                adapter.clearList()
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

    companion object {
        private const val MENU_CLEAR_REQUESTS = Menu.FIRST
    }
}
Loading