Auth: Allow stripping device name from requests
Helps with some banned devices. Enable for -hw build by default.
This commit is contained in:
parent
9d30907c89
commit
2ff9966bf5
8 changed files with 765 additions and 1 deletions
|
|
@ -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"}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
32
play-services-core/src/huawei/AndroidManifest.xml
Normal file
32
play-services-core/src/huawei/AndroidManifest.xml
Normal 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>
|
||||
53
play-services-core/src/huaweilh/AndroidManifest.xml
Normal file
53
play-services-core/src/huaweilh/AndroidManifest.xml
Normal 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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,9 +83,26 @@ This can take a couple of minutes."</string>
|
|||
<string name="prefs_account_security">Sign-in & 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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue