Auth: Allow stripping device name from requests

Helps with some banned devices. Enable for -hw build by default.
This commit is contained in:
Marvin W 2024-02-28 11:26:02 +01:00 • committed by Cuynu
commit 2ff9966bf5
8 changed files with 765 additions and 1 deletions

View file

@ -0,0 +1,216 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.settings
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Binder
object SettingsContract {
fun getAuthority(context: Context) = "${context.packageName}.microg.settings"
fun getAuthorityUri(context: Context): Uri = Uri.parse("content://${getAuthority(context)}")
object CheckIn {
private const val id = "check-in"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val ENABLED = "checkin_enable_service"
const val ANDROID_ID = "androidId"
const val DIGEST = "digest"
const val LAST_CHECK_IN = "lastCheckin"
const val SECURITY_TOKEN = "securityToken"
const val VERSION_INFO = "versionInfo"
const val DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo"
val PROJECTION = arrayOf(
ENABLED,
ANDROID_ID,
DIGEST,
LAST_CHECK_IN,
SECURITY_TOKEN,
VERSION_INFO,
DEVICE_DATA_VERSION_INFO,
)
const val PREFERENCES_NAME = "checkin"
const val INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8"
}
object Gcm {
private const val id = "gcm"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val FULL_LOG = "gcm_full_log"
const val LAST_PERSISTENT_ID = "gcm_last_persistent_id"
const val CONFIRM_NEW_APPS = "gcm_confirm_new_apps"
const val ENABLE_GCM = "gcm_enable_mcs_service"
const val NETWORK_MOBILE = "gcm_network_mobile"
const val NETWORK_WIFI = "gcm_network_wifi"
const val NETWORK_ROAMING = "gcm_network_roaming"
const val NETWORK_OTHER = "gcm_network_other"
const val LEARNT_MOBILE = "gcm_learnt_mobile"
const val LEARNT_WIFI = "gcm_learnt_wifi"
const val LEARNT_OTHER = "gcm_learnt_other"
val PROJECTION = arrayOf(
FULL_LOG,
LAST_PERSISTENT_ID,
CONFIRM_NEW_APPS,
ENABLE_GCM,
NETWORK_MOBILE,
NETWORK_WIFI,
NETWORK_ROAMING,
NETWORK_OTHER,
LEARNT_MOBILE,
LEARNT_WIFI,
LEARNT_OTHER,
)
}
object Auth {
private const val id = "auth"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val TRUST_GOOGLE = "auth_manager_trust_google"
const val VISIBLE = "auth_manager_visible"
const val INCLUDE_ANDROID_ID = "auth_include_android_id"
const val STRIP_DEVICE_NAME = "auth_strip_device_name"
val PROJECTION = arrayOf(
TRUST_GOOGLE,
VISIBLE,
INCLUDE_ANDROID_ID,
STRIP_DEVICE_NAME,
)
}
object Exposure {
private const val id = "exposureNotification"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val SCANNER_ENABLED = "exposure_scanner_enabled"
const val LAST_CLEANUP = "exposure_last_cleanup"
val PROJECTION = arrayOf(
SCANNER_ENABLED,
LAST_CLEANUP,
)
}
object SafetyNet {
private const val id = "safety-net"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val ENABLED = "safetynet_enabled"
val PROJECTION = arrayOf(
ENABLED
)
}
object DroidGuard {
private const val id = "droidguard"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
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,
FORCE_LOCAL_DISABLED,
)
}
object Profile {
private const val id = "profile"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val PROFILE = "device_profile"
const val SERIAL = "device_profile_serial"
val PROJECTION = arrayOf(
PROFILE,
SERIAL
)
}
object Location {
private const val id = "location"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val WIFI_MLS = "location_wifi_mls"
const val WIFI_MOVING = "location_wifi_moving"
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,
)
}
object Vending {
private const val id = "vending"
fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id)
fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id"
const val LICENSING = "vending_licensing"
val PROJECTION = arrayOf(
LICENSING
)
}
private fun <T> withoutCallingIdentity(f: () -> T): T {
val identity = Binder.clearCallingIdentity()
try {
return f.invoke()
} finally {
Binder.restoreCallingIdentity(identity)
}
}
@JvmStatic
fun <T> getSettings(context: Context, uri: Uri, projection: Array<out String>?, f: (Cursor) -> T): T = withoutCallingIdentity {
val c = context.contentResolver.query(uri, projection, null, null, null)
try {
require(c != null) { "Cursor for query $uri ${projection?.toList()} was null" }
if (!c.moveToFirst()) error("Cursor for query $uri ${projection?.toList()} was empty")
f.invoke(c)
} finally {
c?.close()
}
}
@JvmStatic
fun setSettings(context: Context, uri: Uri, v: ContentValues.() -> Unit) = withoutCallingIdentity {
val values = ContentValues().apply { v.invoke(this) }
val affected = context.contentResolver.update(uri, values, null, null)
require(affected == 1) { "Update for $uri with $values affected 0 rows"}
}
}

View file

@ -0,0 +1,421 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.settings
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.Context.MODE_PRIVATE
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
import org.microg.gms.settings.SettingsContract.CheckIn
import org.microg.gms.settings.SettingsContract.DroidGuard
import org.microg.gms.settings.SettingsContract.Exposure
import org.microg.gms.settings.SettingsContract.Gcm
import org.microg.gms.settings.SettingsContract.Location
import org.microg.gms.settings.SettingsContract.Vending
import org.microg.gms.settings.SettingsContract.Profile
import org.microg.gms.settings.SettingsContract.SafetyNet
import org.microg.gms.settings.SettingsContract.getAuthority
import java.io.File
private const val SETTINGS_PREFIX = "org.microg.gms.settings."
/**
* All settings access should go through this [ContentProvider],
* because it provides safe access from different processes which normal [SharedPreferences] don't.
*/
class SettingsProvider : ContentProvider() {
private val preferences: SharedPreferences by lazy {
PreferenceManager.getDefaultSharedPreferences(context)
}
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(
"getSharedPreferences",
File::class.java,
Int::class.javaPrimitiveType
).invoke(context, File("/system/etc/microg.xml"), MODE_PRIVATE) as SharedPreferences
} catch (ignored: Exception) {
null
}
}
private val metaDataPreferences: SharedPreferences by lazy {
MetaDataPreferences(context!!, SETTINGS_PREFIX)
}
override fun onCreate(): Boolean {
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?
): Cursor? = when (uri) {
CheckIn.getContentUri(context!!) -> queryCheckIn(projection ?: CheckIn.PROJECTION)
Gcm.getContentUri(context!!) -> queryGcm(projection ?: Gcm.PROJECTION)
Auth.getContentUri(context!!) -> queryAuth(projection ?: Auth.PROJECTION)
Exposure.getContentUri(context!!) -> queryExposure(projection ?: Exposure.PROJECTION)
SafetyNet.getContentUri(context!!) -> querySafetyNet(projection ?: SafetyNet.PROJECTION)
DroidGuard.getContentUri(context!!) -> queryDroidGuard(projection ?: DroidGuard.PROJECTION)
Profile.getContentUri(context!!) -> queryProfile(projection ?: Profile.PROJECTION)
Location.getContentUri(context!!) -> queryLocation(projection ?: Location.PROJECTION)
Vending.getContentUri(context!!) -> queryVending(projection ?: Vending.PROJECTION)
else -> null
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?
): Int {
warnIfNotMainProcess(context, this.javaClass)
if (values == null) return 0
when (uri) {
CheckIn.getContentUri(context!!) -> updateCheckIn(values)
Gcm.getContentUri(context!!) -> updateGcm(values)
Auth.getContentUri(context!!) -> updateAuth(values)
Exposure.getContentUri(context!!) -> updateExposure(values)
SafetyNet.getContentUri(context!!) -> updateSafetyNet(values)
DroidGuard.getContentUri(context!!) -> updateDroidGuard(values)
Profile.getContentUri(context!!) -> updateProfile(values)
Location.getContentUri(context!!) -> updateLocation(values)
Vending.getContentUri(context!!) -> updateVending(values)
else -> return 0
}
return 1
}
private fun queryCheckIn(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
CheckIn.ENABLED -> getSettingsBoolean(key, false)
CheckIn.ANDROID_ID -> checkInPrefs.getLong(key, 0)
CheckIn.DIGEST -> checkInPrefs.getString(key, CheckIn.INITIAL_DIGEST)
?: CheckIn.INITIAL_DIGEST
CheckIn.LAST_CHECK_IN -> checkInPrefs.getLong(key, 0)
CheckIn.SECURITY_TOKEN -> checkInPrefs.getLong(key, 0)
CheckIn.VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
CheckIn.DEVICE_DATA_VERSION_INFO -> checkInPrefs.getString(key, "") ?: ""
else -> throw IllegalArgumentException()
}
}
private fun updateCheckIn(values: ContentValues) {
if (values.size() == 0) return
if (values.size() == 1 && values.containsKey(CheckIn.ENABLED)) {
// special case: only changing enabled state
updateCheckInEnabled(values.getAsBoolean(CheckIn.ENABLED))
return
}
val editor = checkInPrefs.edit()
values.valueSet().forEach { (key, value) ->
if (key == CheckIn.ENABLED) {
// special case: not saved in checkInPrefs
updateCheckInEnabled(value as Boolean)
}
when (key) {
CheckIn.ANDROID_ID -> editor.putLong(key, value as Long)
CheckIn.DIGEST -> editor.putString(key, value as String?)
CheckIn.LAST_CHECK_IN -> editor.putLong(key, value as Long)
CheckIn.SECURITY_TOKEN -> editor.putLong(key, value as Long)
CheckIn.VERSION_INFO -> editor.putString(key, value as String?)
CheckIn.DEVICE_DATA_VERSION_INFO -> editor.putString(key, value as String?)
}
}
editor.apply()
}
private fun updateCheckInEnabled(enabled: Boolean) {
preferences.edit()
.putBoolean(CheckIn.ENABLED, enabled)
.apply()
}
private fun queryGcm(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Gcm.ENABLE_GCM -> getSettingsBoolean(key, false)
Gcm.FULL_LOG -> getSettingsBoolean(key, true)
Gcm.CONFIRM_NEW_APPS -> getSettingsBoolean(key, false)
Gcm.LAST_PERSISTENT_ID -> preferences.getString(key, "") ?: ""
Gcm.NETWORK_MOBILE -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
Gcm.NETWORK_WIFI -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
Gcm.NETWORK_ROAMING -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
Gcm.NETWORK_OTHER -> Integer.parseInt(preferences.getString(key, "0") ?: "0")
Gcm.LEARNT_MOBILE -> preferences.getInt(key, 300000)
Gcm.LEARNT_WIFI -> preferences.getInt(key, 300000)
Gcm.LEARNT_OTHER -> preferences.getInt(key, 300000)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateGcm(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Gcm.ENABLE_GCM -> editor.putBoolean(key, value as Boolean)
Gcm.FULL_LOG -> editor.putBoolean(key, value as Boolean)
Gcm.CONFIRM_NEW_APPS -> editor.putBoolean(key, value as Boolean)
Gcm.LAST_PERSISTENT_ID -> editor.putString(key, value as String?)
Gcm.NETWORK_MOBILE -> editor.putString(key, (value as Int).toString())
Gcm.NETWORK_WIFI -> editor.putString(key, (value as Int).toString())
Gcm.NETWORK_ROAMING -> editor.putString(key, (value as Int).toString())
Gcm.NETWORK_OTHER -> editor.putString(key, (value as Int).toString())
Gcm.LEARNT_MOBILE -> editor.putInt(key, value as Int)
Gcm.LEARNT_WIFI -> editor.putInt(key, value as Int)
Gcm.LEARNT_OTHER -> editor.putInt(key, value as Int)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryAuth(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Auth.TRUST_GOOGLE -> getSettingsBoolean(key, true)
Auth.VISIBLE -> getSettingsBoolean(key, false)
Auth.INCLUDE_ANDROID_ID -> getSettingsBoolean(key, true)
Auth.STRIP_DEVICE_NAME -> getSettingsBoolean(key, false)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateAuth(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Auth.TRUST_GOOGLE -> editor.putBoolean(key, value as Boolean)
Auth.VISIBLE -> editor.putBoolean(key, value as Boolean)
Auth.INCLUDE_ANDROID_ID -> editor.putBoolean(key, value as Boolean)
Auth.STRIP_DEVICE_NAME -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryExposure(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Exposure.SCANNER_ENABLED -> getSettingsBoolean(key, false)
Exposure.LAST_CLEANUP -> preferences.getLong(key, 0L)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateExposure(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Exposure.SCANNER_ENABLED -> editor.putBoolean(key, value as Boolean)
Exposure.LAST_CLEANUP -> editor.putLong(key, value as Long)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun querySafetyNet(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
SafetyNet.ENABLED -> getSettingsBoolean(key, false)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateSafetyNet(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
SafetyNet.ENABLED -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryDroidGuard(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
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")
}
}
private fun updateDroidGuard(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
DroidGuard.ENABLED -> editor.putBoolean(key, value as Boolean)
DroidGuard.MODE -> editor.putString(key, value as String)
DroidGuard.NETWORK_SERVER_URL -> editor.putString(key, value as String)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryProfile(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Profile.PROFILE -> getSettingsString(key, "auto")
Profile.SERIAL -> getSettingsString(key)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateProfile(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Profile.PROFILE -> editor.putString(key, value as String?)
Profile.SERIAL -> editor.putString(key, value as String?)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryLocation(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
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
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Location.WIFI_MLS -> editor.putBoolean(key, value as Boolean)
Location.WIFI_MOVING -> editor.putBoolean(key, value as Boolean)
Location.WIFI_LEARNING -> editor.putBoolean(key, value as Boolean)
Location.CELL_MLS -> editor.putBoolean(key, value as Boolean)
Location.CELL_LEARNING -> editor.putBoolean(key, value as Boolean)
Location.GEOCODER_NOMINATIM -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun queryVending(p: Array<out String>): Cursor = MatrixCursor(p).addRow(p) { key ->
when (key) {
Vending.LICENSING -> getSettingsBoolean(key, false)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
private fun updateVending(values: ContentValues) {
if (values.size() == 0) return
val editor = preferences.edit()
values.valueSet().forEach { (key, value) ->
when (key) {
Vending.LICENSING -> editor.putBoolean(key, value as Boolean)
else -> throw IllegalArgumentException("Unknown key: $key")
}
}
editor.apply()
}
private fun MatrixCursor.addRow(
p: Array<out String>,
valueGetter: (String) -> Any?
): MatrixCursor {
val row = newRow()
for (key in p) row.add(valueGetter.invoke(key))
return this
}
override fun getType(uri: Uri): String {
return "vnd.android.cursor.item/vnd.${getAuthority(context!!)}.${uri.path}"
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
throw UnsupportedOperationException()
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
throw UnsupportedOperationException()
}
/**
* Returns the current setting of the given [key]
* using the default value from [systemDefaultPreferences] or [def] if not available.
* @return the current setting as [Int], because [ContentProvider] does not support [Boolean].
*/
private fun getSettingsBoolean(key: String, def: Boolean): Int {
return listOf(preferences, systemDefaultPreferences, metaDataPreferences).getBooleanAsInt(key, def)
}
private fun getSettingsString(key: String, def: String? = null): String? = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getString(key, def)
private fun getSettingsInt(key: String, def: Int): Int = listOf(preferences, systemDefaultPreferences, metaDataPreferences).getInt(key, def)
private fun getSettingsLong(key: String, def: Long): Long = listOf(preferences, systemDefaultPreferences, metaDataPreferences).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 }
private fun List<SharedPreferences?>.getBoolean(key: String, def: Boolean): Boolean = foldRight(def) { preferences, defValue -> preferences?.getBoolean(key, defValue) ?: defValue }
private fun List<SharedPreferences?>.getBooleanAsInt(key: String, def: Boolean): Int = if (getBoolean(key, def)) 1 else 0
}

View file

@ -0,0 +1,32 @@
<!--
~ SPDX-FileCopyrightText: 2023 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<meta-data
android:name="org.microg.gms.settings.checkin_enable_service"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.gcm_enable_mcs_service"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.auth_manager_visible"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.auth_include_android_id"
android:value="false" />
<meta-data
android:name="org.microg.gms.settings.auth_strip_device_name"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.droidguard_enabled"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.safetynet_enabled"
android:value="true" />
</application>
</manifest>

View file

@ -0,0 +1,53 @@
<!--
~ SPDX-FileCopyrightText: 2023 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<meta-data
android:name="org.microg.gms.settings.checkin_enable_service"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.gcm_enable_mcs_service"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.auth_manager_visible"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.auth_include_android_id"
android:value="false" />
<meta-data
android:name="org.microg.gms.settings.auth_strip_device_name"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.droidguard_enabled"
android:value="true" />
<meta-data
android:name="org.microg.gms.settings.safetynet_enabled"
android:value="true" />
<activity-alias
android:name="org.microg.gms.ui.SettingsActivity"
android:targetActivity="org.microg.gms.ui.MainSettingsActivity"
tools:node="remove" />
<activity-alias
android:name="org.lighthouse.SettingsActivity"
android:icon="@mipmap/ic_app_settings"
android:label="@string/gms_settings_name"
android:roundIcon="@mipmap/ic_app_settings"
android:process=":ui"
android:targetActivity="org.microg.gms.ui.MainSettingsActivity"
android:taskAffinity="org.microg.gms.settings"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
</manifest>

View file

@ -113,7 +113,17 @@ public class AuthRequest extends HttpFormClient.Request {
public AuthRequest fromContext(Context context) {
build(context);
locale(Utils.getLocale(context));
<<<<<<< HEAD
androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
=======
if (AuthPrefs.shouldIncludeAndroidId(context)) {
androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
}
if (AuthPrefs.shouldStripDeviceName(context)) {
deviceName = "";
buildVersion = "";
}
>>>>>>> 9028d03a (Auth: Allow stripping device name from requests)
return this;
}

View file

@ -24,4 +24,11 @@ object AuthPrefs {
}
}
@JvmStatic
fun shouldStripDeviceName(context: Context): Boolean {
return SettingsContract.getSettings(context, Auth.getContentUri(context), arrayOf(Auth.STRIP_DEVICE_NAME)) { c ->
c.getInt(0) != 0
}
}
}

View file

@ -83,9 +83,26 @@ This can take a couple of minutes."</string>
<string name="prefs_account_security">Sign-in &amp; security</string>
<string name="pref_auth_trust_google_title">Trust Google for app permissions</string>
<string name="pref_auth_trust_google_summary">When disabled, the user is asked before an apps authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>
<string name="pref_auth_trust_google_summary">When disabled, the user is asked before an app\'s authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>
<string name="pref_auth_visible_title">Allow apps to find accounts</string>
<string name="pref_auth_visible_summary">When enabled, all applications on this device will be able to see email address of your Google Accounts without prior authorization.</string>
<<<<<<< HEAD
=======
<string name="pref_auth_include_android_id_title">Authenticate with device registration</string>
<string name="pref_auth_include_android_id_summary">When disabled, authentication requests won\'t be linked to the device registration, which may allow unauthorized devices to sign in, but may have unforeseen consequences.</string>
<string name="pref_auth_strip_device_name_title">Strip device name for authentication</string>
<string name="pref_auth_strip_device_name_summary">When enabled, authentication requests won\'t include the device\'s name, which may allow unauthorized devices to sign in, but may have unforeseen consequences.</string>
<string name="pref_checkin_enable_summary">Registers your device to Google services and creates a unique device identifier. microG strips identifying bits other than your Google account name from registration data.</string>
<string name="pref_device_registration_android_id">Android ID</string>
<string name="checkin_not_registered">Not registered</string>
<string name="checkin_last_registration">Last registration: <xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
<string name="checkin_enable_switch">Register device</string>
<string name="pref_info_status">Status</string>
<string name="pref_more_settings">More</string>
>>>>>>> 9028d03a (Auth: Allow stripping device name from requests)
<string name="pref_add_account_title">Account</string>
<string name="pref_add_account_summary">Add Google account</string>

View file

@ -58,7 +58,15 @@
android:key="auth_include_android_id"
android:summary="@string/pref_auth_include_android_id_summary"
android:title="@string/pref_auth_include_android_id_title"/>
<<<<<<< HEAD
>>>>>>> 566215bd (UI: Port more to Material 3)
=======
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="auth_strip_device_name"
android:summary="@string/pref_auth_strip_device_name_summary"
android:title="@string/pref_auth_strip_device_name_title"/>
>>>>>>> 9028d03a (Auth: Allow stripping device name from requests)
</PreferenceCategory>
<Preference