Skip to content

Commit

Permalink
DroidGuard/SafetyNet/Location: Improve configurability and fix defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
mar-v-in committed Jul 6, 2023
1 parent 11a8aa7 commit 4772008
Show file tree
Hide file tree
Showing 19 changed files with 123 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,13 @@ object SettingsContract {
const val ENABLED = "droidguard_enabled"
const val MODE = "droidguard_mode"
const val NETWORK_SERVER_URL = "droidguard_network_server_url"
const val FORCE_LOCAL_DISABLED = "droidguard_force_local_disabled"

val PROJECTION = arrayOf(
ENABLED,
MODE,
NETWORK_SERVER_URL
NETWORK_SERVER_URL,
FORCE_LOCAL_DISABLED,
)
}

Expand Down Expand Up @@ -155,13 +157,15 @@ object SettingsContract {
const val WIFI_LEARNING = "location_wifi_learning"
const val CELL_MLS = "location_cell_mls"
const val CELL_LEARNING = "location_cell_learning"
const val GEOCODER_NOMINATIM = "location_geocoder_nominatim"

val PROJECTION = arrayOf(
WIFI_MLS,
WIFI_MOVING,
WIFI_LEARNING,
CELL_MLS,
CELL_LEARNING,
GEOCODER_NOMINATIM,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.content.SharedPreferences
import android.database.Cursor
import android.database.MatrixCursor
import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.preference.PreferenceManager
import org.microg.gms.common.PackageUtils.warnIfNotMainProcess
import org.microg.gms.settings.SettingsContract.Auth
Expand All @@ -38,6 +39,9 @@ class SettingsProvider : ContentProvider() {
private val checkInPrefs by lazy {
context!!.getSharedPreferences(CheckIn.PREFERENCES_NAME, MODE_PRIVATE)
}
private val unifiedNlpPreferences by lazy {
context!!.getSharedPreferences("unified_nlp", MODE_PRIVATE)
}
private val systemDefaultPreferences: SharedPreferences? by lazy {
try {
Context::class.java.getDeclaredMethod(
Expand Down Expand Up @@ -252,6 +256,7 @@ class SettingsProvider : ContentProvider() {
DroidGuard.ENABLED -> getSettingsBoolean(key, false)
DroidGuard.MODE -> getSettingsString(key)
DroidGuard.NETWORK_SERVER_URL -> getSettingsString(key)
DroidGuard.FORCE_LOCAL_DISABLED -> systemDefaultPreferences?.getBoolean(key, false) ?: false
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
Expand Down Expand Up @@ -293,14 +298,18 @@ class SettingsProvider : ContentProvider() {

private fun queryLocation(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Location.WIFI_MLS -> getSettingsBoolean(key, true)
Location.WIFI_MOVING -> getSettingsBoolean(key, true)
Location.WIFI_LEARNING -> getSettingsBoolean(key, true)
Location.CELL_MLS -> getSettingsBoolean(key, true)
Location.CELL_LEARNING -> getSettingsBoolean(key, true)
Location.WIFI_MLS -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend("org.microg.nlp.backend.ichnaea"))
Location.WIFI_MOVING -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend("de.sorunome.unifiednlp.trains"))
Location.WIFI_LEARNING -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend("helium314.localbackend", "org.fitchfamily.android.dejavu"))
Location.CELL_MLS -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend("org.microg.nlp.backend.ichnaea"))
Location.CELL_LEARNING -> getSettingsBoolean(key, hasUnifiedNlpLocationBackend("helium314.localbackend", "org.fitchfamily.android.dejavu"))
Location.GEOCODER_NOMINATIM -> getSettingsBoolean(key, hasUnifiedNlpGeocoderBackend("org.microg.nlp.backend.nominatim") )
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun hasUnifiedNlpPrefixInStringSet(key: String, vararg prefixes: String) = getUnifiedNlpSettingsStringSetCompat(key, emptySet()).any { entry -> prefixes.any { prefix -> entry.startsWith(prefix)}}
private fun hasUnifiedNlpLocationBackend(vararg packageNames: String) = hasUnifiedNlpPrefixInStringSet("location_backends", *packageNames.map { "$it/" }.toTypedArray())
private fun hasUnifiedNlpGeocoderBackend(vararg packageNames: String) = hasUnifiedNlpPrefixInStringSet("geocoder_backends", *packageNames.map { "$it/" }.toTypedArray())

private fun updateLocation(values: ContentValues) {
if (values.size() == 0) return
Expand Down Expand Up @@ -351,7 +360,27 @@ class SettingsProvider : ContentProvider() {
private fun getSettingsString(key: String, def: String? = null): String? = listOf(preferences, systemDefaultPreferences).getString(key, def)
private fun getSettingsInt(key: String, def: Int): Int = listOf(preferences, systemDefaultPreferences).getInt(key, def)
private fun getSettingsLong(key: String, def: Long): Long = listOf(preferences, systemDefaultPreferences).getLong(key, def)
private fun getUnifiedNlpSettingsStringSetCompat(key: String, def: Set<String>): Set<String> = listOf(unifiedNlpPreferences, preferences, systemDefaultPreferences).getStringSetCompat(key, def)

private fun SharedPreferences.getStringSetCompat(key: String, def: Set<String>): Set<String> {
if (SDK_INT >= 11) {
try {
val res = getStringSet(key, null)
if (res != null) return res.filter { it.isNotEmpty() }.toSet()
} catch (ignored: Exception) {
// Ignore
}
}
try {
val str = getString(key, null)
if (str != null) return str.split("\\|".toRegex()).filter { it.isNotEmpty() }.toSet()
} catch (ignored: Exception) {
// Ignore
}
return def
}

private fun List<SharedPreferences?>.getStringSetCompat(key: String, def: Set<String>): Set<String> = foldRight(def) { preferences, defValue -> preferences?.getStringSetCompat(key, defValue) ?: defValue }
private fun List<SharedPreferences?>.getString(key: String, def: String?): String? = foldRight(def) { preferences, defValue -> preferences?.getString(key, defValue) ?: defValue }
private fun List<SharedPreferences?>.getInt(key: String, def: Int): Int = foldRight(def) { preferences, defValue -> preferences?.getInt(key, defValue) ?: defValue }
private fun List<SharedPreferences?>.getLong(key: String, def: Long): Long = foldRight(def) { preferences, defValue -> preferences?.getLong(key, defValue) ?: defValue }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class SafetyNetFragment : PreferenceFragmentCompat() {
private lateinit var apps: PreferenceCategory
private lateinit var appsAll: Preference
private lateinit var appsNone: Preference
private lateinit var droidguardUnsupported: Preference

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_safetynet)
Expand All @@ -62,6 +63,7 @@ class SafetyNetFragment : PreferenceFragmentCompat() {
apps = preferenceScreen.findPreference("prefcat_safetynet_apps") ?: apps
appsAll = preferenceScreen.findPreference("pref_safetynet_apps_all") ?: appsAll
appsNone = preferenceScreen.findPreference("pref_safetynet_apps_none") ?: appsNone
droidguardUnsupported = preferenceScreen.findPreference("pref_droidguard_unsupported") ?: droidguardUnsupported

runAttest.isVisible = SAFETYNET_API_KEY != null
runReCaptcha.isVisible = RECAPTCHA_SITE_KEY != null
Expand All @@ -75,6 +77,7 @@ class SafetyNetFragment : PreferenceFragmentCompat() {
val newStatus = newValue as Boolean
SafetyNetPreferences.setEnabled(requireContext(), newStatus)
DroidGuardPreferences.setEnabled(requireContext(), newStatus)
droidguardUnsupported.isVisible = switchBarPreference.isChecked && !DroidGuardPreferences.isAvailable(requireContext())
true
}
}
Expand Down Expand Up @@ -218,6 +221,7 @@ class SafetyNetFragment : PreferenceFragmentCompat() {

switchBarPreference.isEnabled = CheckinPreferences.isEnabled(requireContext())
switchBarPreference.isChecked = SafetyNetPreferences.isEnabled(requireContext()) && DroidGuardPreferences.isEnabled(requireContext())
droidguardUnsupported.isVisible = switchBarPreference.isChecked && !DroidGuardPreferences.isAvailable(requireContext())

updateContent()
}
Expand Down
1 change: 1 addition & 0 deletions play-services-core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ This can take a couple of minutes."</string>
<string name="pref_test_summary_warn">Warning: %s</string>
<string name="pref_test_summary_running">Running…</string>
<string name="pref_droidguard_operation_mode">Operation mode</string>
<string name="pref_droidguard_unsupported_summary">DroidGuard execution is unsupported on this device. SafetyNet services may misbehave.</string>
<string name="prefcat_safetynet_apps_title">Apps using SafetyNet</string>
<string name="menu_clear_recent_requests">Clear recent requests</string>
<string name="safetynet_last_run_at">Last use: <xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
Expand Down
7 changes: 7 additions & 0 deletions play-services-core/src/main/res/xml/preferences_safetynet.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,12 @@
android:key="pref_safetynet_summary"
android:selectable="false"
android:summary="@string/safetynet_intro" />
<Preference
app:isPreferenceVisible="false"
tools:isPreferenceVisible="true"
android:icon="@drawable/ic_alert"
android:key="pref_droidguard_unsupported"
android:selectable="false"
android:summary="@string/pref_droidguard_unsupported_summary" />
</PreferenceCategory>
</PreferenceScreen>
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,14 @@ private final void c(byte[] data) {
} else {
Log.d("GmsGuardChimera", "c(null)", new RuntimeException().fillInStackTrace());
}
byte[] bytes = b.createPingHandle(getPackageName(), "full", b(""), ping).run(Collections.emptyMap());
Log.d("GmsGuardChimera", "c.bytes = " + Base64.encodeToString(bytes, Base64.NO_WRAP));
Request fastRequest = b.createRequest("fast", getPackageName(), null, bytes);
b.fetchFromServer("fast", fastRequest);
try {
byte[] bytes = b.createPingHandle(getPackageName(), "full", b(""), ping).run(Collections.emptyMap());
Log.d("GmsGuardChimera", "c.bytes = " + Base64.encodeToString(bytes, Base64.NO_WRAP));
Request fastRequest = b.createRequest("fast", getPackageName(), null, bytes);
b.fetchFromServer("fast", fastRequest);
} catch (Exception e) {
Log.w("GmsGuardChimera", e);
}
}

// handle intent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.database.Cursor
import androidx.core.database.getStringOrNull
import org.microg.gms.settings.SettingsContract
import org.microg.gms.settings.SettingsContract.DroidGuard.ENABLED
import org.microg.gms.settings.SettingsContract.DroidGuard.FORCE_LOCAL_DISABLED
import org.microg.gms.settings.SettingsContract.DroidGuard.MODE
import org.microg.gms.settings.SettingsContract.DroidGuard.NETWORK_SERVER_URL

Expand All @@ -27,9 +28,18 @@ object DroidGuardPreferences {
private fun setSettings(context: Context, f: ContentValues.() -> Unit) =
SettingsContract.setSettings(context, SettingsContract.DroidGuard.getContentUri(context), f)

@JvmStatic
fun isForcedLocalDisabled(context: Context): Boolean = getSettings(context, FORCE_LOCAL_DISABLED, false) { it.getInt(0) != 0 }

@JvmStatic
fun isEnabled(context: Context): Boolean = getSettings(context, ENABLED, false) { it.getInt(0) != 0 }

@JvmStatic
fun isAvailable(context: Context): Boolean = isEnabled(context) && (!isForcedLocalDisabled(context) || getMode(context) != Mode.Embedded)

@JvmStatic
fun isLocalAvailable(context: Context): Boolean = isEnabled(context) && !isForcedLocalDisabled(context)

@JvmStatic
fun setEnabled(context: Context, enabled: Boolean) = setSettings(context) { put(ENABLED, enabled) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface DroidGuardResultCreator {

companion object {
fun getInstance(context: Context): DroidGuardResultCreator =
if (DroidGuardPreferences.isEnabled(context)) {
if (DroidGuardPreferences.isAvailable(context)) {
when (DroidGuardPreferences.getMode(context)) {
DroidGuardPreferences.Mode.Embedded -> EmbeddedDroidGuardResultCreator(context)
DroidGuardPreferences.Mode.Network -> NetworkDroidGuardResultCreator(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,19 @@ class HandleProxyFactory(private val context: Context) {
private val queue = Volley.newRequestQueue(context)

fun createHandle(packageName: String, flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = readFromDatabase(flow) ?: fetchFromServer(flow, packageName)
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)
}

fun createPingHandle(packageName: String, flow: String, callback: GuardCallback, pingData: PingData?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = fetchFromServer(flow, createRequest(flow, packageName, pingData))
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, DroidGuardResultsRequest().also { it.clientVersion = 0 })
}

fun createLowLatencyHandle(flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = readFromDatabase("fast") ?: throw Exception("low latency (fast) flow not available")
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class DroidGuardPreferencesFragment : PreferenceFragmentCompat() {
modeNetwork.textChangedListener = {
DroidGuardPreferences.setNetworkServerUrl(requireContext(), it)
}
modeEmbedded.isEnabled = !DroidGuardPreferences.isForcedLocalDisabled(requireContext())
updateConfiguration()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
<Preference
android:icon="@drawable/ic_radio_unchecked"
android:key="pref_droidguard_mode_embedded"
android:persistent="false"
android:summary="@string/pref_droidguard_mode_embedded_summary"
android:title="@string/pref_droidguard_mode_embedded_title" />
<org.microg.gms.droidguard.core.ui.ContainedEditTextPreference
android:icon="@drawable/ic_radio_unchecked"
android:key="pref_droidguard_mode_network"
android:persistent="false"
android:summary="@string/pref_droidguard_mode_network_summary"
android:title="@string/pref_droidguard_mode_network_title" />
</PreferenceCategory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@ class LocationSettings(private val context: Context) {
set(value) {
SettingsContract.setSettings(context, SettingsContract.Location.getContentUri(context)) { put(SettingsContract.Location.CELL_LEARNING, value)}
}

var geocoderNominatim: Boolean
get() = SettingsContract.getSettings(context, SettingsContract.Location.getContentUri(context), arrayOf(SettingsContract.Location.GEOCODER_NOMINATIM)) { c ->
c.getInt(0) != 0
}
set(value) {
SettingsContract.setSettings(context, SettingsContract.Location.getContentUri(context)) { put(SettingsContract.Location.GEOCODER_NOMINATIM, value)}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package org.microg.gms.location.provider
import android.app.Service
import android.content.Intent
import android.os.IBinder
import java.io.FileDescriptor
import java.io.PrintWriter

class GeocodeProviderService : Service() {
private var bound: Boolean = false
Expand All @@ -20,4 +22,8 @@ class GeocodeProviderService : Service() {
bound = true
return provider?.binder
}

override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
provider?.dump(writer)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import com.android.volley.toolbox.Volley
import com.google.android.gms.location.internal.ClientIdentity
import org.json.JSONObject
import org.microg.address.Formatter
import org.microg.gms.location.LocationSettings
import java.io.PrintWriter
import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
Expand All @@ -28,10 +30,12 @@ class OpenStreetMapNominatimGeocodeProvider(private val context: Context) : Geoc
private val queue = Volley.newRequestQueue(context)
private val formatter = runCatching { Formatter() }.getOrNull()
private val addressCache = LruCache<CacheKey, Address>(CACHE_SIZE)
private val settings by lazy { LocationSettings(context) }

override fun onGetFromLocation(latitude: Double, longitude: Double, maxResults: Int, params: GeocoderParams, addresses: MutableList<Address>): String? {
val clientIdentity = params.clientIdentity ?: return "null client package"
val locale = params.locale ?: return "null locale"
if (!settings.geocoderNominatim) return "disabled"
val cacheKey = CacheKey(clientIdentity, locale, latitude, longitude)
addressCache[cacheKey]?.let {address ->
addresses.add(address)
Expand Down Expand Up @@ -79,6 +83,7 @@ class OpenStreetMapNominatimGeocodeProvider(private val context: Context) : Geoc
): String? {
val clientIdentity = params.clientIdentity ?: return "null client package"
val locale = params.locale ?: return "null locale"
if (!settings.geocoderNominatim) return "disabled"
val uri = Uri.Builder()
.scheme("https").authority(NOMINATIM_SERVER).path("/search")
.appendQueryParameter("format", "json")
Expand Down Expand Up @@ -149,6 +154,11 @@ class OpenStreetMapNominatimGeocodeProvider(private val context: Context) : Geoc
return address
}

fun dump(writer: PrintWriter?) {
writer?.println("Enabled: ${settings.geocoderNominatim}")
writer?.println("Address cache: size=${addressCache.size()} hits=${addressCache.hitCount()} miss=${addressCache.missCount()} puts=${addressCache.putCount()} evicts=${addressCache.evictionCount()}")
}

companion object {
private const val CACHE_SIZE = 200

Expand Down

0 comments on commit 4772008

Please sign in to comment.