Server trust feature (#3410)

* Server trust feature

* Always allow clear_notification, remove_channel and command_stop_tts commands
This commit is contained in:
Joris Pelgröm 2023-03-16 00:14:39 +01:00 committed by GitHub
parent 0d9ea48fa7
commit 1a7091a761
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 183 additions and 177 deletions

View file

@ -28,6 +28,7 @@ class LaunchPresenterImpl @Inject constructor(
getMessagingToken()
)
)
serverManager.integrationRepository(it.id).getConfig() // Update cached data
} catch (e: Exception) {
Log.e(TAG, "Issue updating Registration", e)
}

View file

@ -212,7 +212,6 @@ class MessagingManager @Inject constructor(
COMMAND_LAUNCH_APP,
COMMAND_APP_LOCK,
COMMAND_PERSISTENT_CONNECTION,
TextToSpeechData.COMMAND_STOP_TTS,
COMMAND_AUTO_SCREEN_BRIGHTNESS,
COMMAND_SCREEN_BRIGHTNESS_LEVEL,
COMMAND_SCREEN_OFF_TIMEOUT
@ -295,40 +294,40 @@ class MessagingManager @Inject constructor(
} ?: ServerManager.SERVER_ID_ACTIVE
jsonData = jsonData + mutableMapOf<String, String>().apply { put(THIS_SERVER_ID, serverId.toString()) }
when {
jsonData[NotificationData.MESSAGE] == REQUEST_LOCATION_UPDATE -> {
Log.d(TAG, "Request location update")
requestAccurateLocationUpdate()
}
jsonData[NotificationData.MESSAGE] == CLEAR_NOTIFICATION && !jsonData["tag"].isNullOrBlank() -> {
Log.d(TAG, "Clearing notification with tag: ${jsonData["tag"]}")
clearNotification(jsonData["tag"]!!)
}
jsonData[NotificationData.MESSAGE] == REMOVE_CHANNEL && !jsonData[NotificationData.CHANNEL].isNullOrBlank() -> {
Log.d(TAG, "Removing Notification channel ${jsonData[NotificationData.CHANNEL]}")
removeNotificationChannel(jsonData[NotificationData.CHANNEL]!!)
}
jsonData[NotificationData.MESSAGE] == TextToSpeechData.TTS -> {
speakText(context, jsonData)
}
jsonData[NotificationData.MESSAGE] in DEVICE_COMMANDS -> {
Log.d(TAG, "Processing device command")
when (jsonData[NotificationData.MESSAGE]) {
COMMAND_DND -> {
if (jsonData[NotificationData.COMMAND] in DND_COMMANDS) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
mainScope.launch {
val allowCommands = serverManager.integrationRepository(serverId).isTrusted()
when {
jsonData[NotificationData.MESSAGE] == REQUEST_LOCATION_UPDATE && allowCommands -> {
Log.d(TAG, "Request location update")
requestAccurateLocationUpdate()
}
jsonData[NotificationData.MESSAGE] == CLEAR_NOTIFICATION && !jsonData["tag"].isNullOrBlank() -> {
Log.d(TAG, "Clearing notification with tag: ${jsonData["tag"]}")
clearNotification(jsonData["tag"]!!)
}
jsonData[NotificationData.MESSAGE] == REMOVE_CHANNEL && !jsonData[NotificationData.CHANNEL].isNullOrBlank() -> {
Log.d(TAG, "Removing Notification channel ${jsonData[NotificationData.CHANNEL]}")
removeNotificationChannel(jsonData[NotificationData.CHANNEL]!!)
}
jsonData[NotificationData.MESSAGE] == TextToSpeechData.TTS -> {
speakText(context, jsonData)
}
jsonData[NotificationData.MESSAGE] == TextToSpeechData.COMMAND_STOP_TTS -> stopTTS()
jsonData[NotificationData.MESSAGE] in DEVICE_COMMANDS && allowCommands -> {
Log.d(TAG, "Processing device command")
when (jsonData[NotificationData.MESSAGE]) {
COMMAND_DND -> {
if (jsonData[NotificationData.COMMAND] in DND_COMMANDS) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Posting notification to device as it does not support DND commands"
)
sendNotification(jsonData)
}
}
} else {
mainScope.launch {
} else {
Log.d(
TAG,
"Invalid DND command received, posting notification to device"
@ -336,12 +335,10 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_RINGER_MODE -> {
if (jsonData[NotificationData.COMMAND] in RM_COMMANDS) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_RINGER_MODE -> {
if (jsonData[NotificationData.COMMAND] in RM_COMMANDS) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid ringer mode command received, posting notification to device"
@ -349,12 +346,10 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_BROADCAST_INTENT -> {
if (!jsonData[INTENT_ACTION].isNullOrEmpty() && !jsonData[INTENT_PACKAGE_NAME].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_BROADCAST_INTENT -> {
if (!jsonData[INTENT_ACTION].isNullOrEmpty() && !jsonData[INTENT_PACKAGE_NAME].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid broadcast command received, posting notification to device"
@ -362,14 +357,12 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_VOLUME_LEVEL -> {
if (!jsonData[NotificationData.MEDIA_STREAM].isNullOrEmpty() && jsonData[NotificationData.MEDIA_STREAM] in CHANNEL_VOLUME_STREAM &&
!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null
) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_VOLUME_LEVEL -> {
if (!jsonData[NotificationData.MEDIA_STREAM].isNullOrEmpty() && jsonData[NotificationData.MEDIA_STREAM] in CHANNEL_VOLUME_STREAM &&
!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null
) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid volume command received, posting notification to device"
@ -377,16 +370,14 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_BLUETOOTH -> {
if (
!jsonData[NotificationData.COMMAND].isNullOrEmpty() &&
jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_BLUETOOTH -> {
if (
!jsonData[NotificationData.COMMAND].isNullOrEmpty() &&
jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid bluetooth command received, posting notification to device"
@ -394,32 +385,26 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
DeviceCommandData.COMMAND_BLE_TRANSMITTER -> {
if (!commandBleTransmitter(context, jsonData, sensorDao, mainScope)) {
mainScope.launch {
DeviceCommandData.COMMAND_BLE_TRANSMITTER -> {
if (!commandBleTransmitter(context, jsonData, sensorDao, mainScope)) {
sendNotification(jsonData)
}
}
}
DeviceCommandData.COMMAND_BEACON_MONITOR -> {
if (!commandBeaconMonitor(context, jsonData)) {
mainScope.launch {
DeviceCommandData.COMMAND_BEACON_MONITOR -> {
if (!commandBeaconMonitor(context, jsonData)) {
sendNotification(jsonData)
}
}
}
COMMAND_HIGH_ACCURACY_MODE -> {
if ((!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) ||
(!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in FORCE_COMMANDS) ||
(
!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] == HIGH_ACCURACY_SET_UPDATE_INTERVAL &&
jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toIntOrNull() != null && jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toInt()!! >= 5
)
) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_HIGH_ACCURACY_MODE -> {
if ((!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) ||
(!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in FORCE_COMMANDS) ||
(
!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] == HIGH_ACCURACY_SET_UPDATE_INTERVAL &&
jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toIntOrNull() != null && jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toInt()!! >= 5
)
) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid high accuracy mode command received, posting notification to device"
@ -427,12 +412,10 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_ACTIVITY -> {
if (!jsonData[INTENT_ACTION].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_ACTIVITY -> {
if (!jsonData[INTENT_ACTION].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid activity command received, posting notification to device"
@ -440,25 +423,23 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_APP_LOCK -> {
val appLockEnablePresent = jsonData[APP_LOCK_ENABLED] != null
val appLockTimeoutPresent = jsonData[APP_LOCK_TIMEOUT] != null
val homeBypassEnablePresent = jsonData[HOME_BYPASS_ENABLED] != null
COMMAND_APP_LOCK -> {
val appLockEnablePresent = jsonData[APP_LOCK_ENABLED] != null
val appLockTimeoutPresent = jsonData[APP_LOCK_TIMEOUT] != null
val homeBypassEnablePresent = jsonData[HOME_BYPASS_ENABLED] != null
val appLockEnableValue = jsonData[APP_LOCK_ENABLED]?.lowercase()?.toBooleanStrictOrNull()
val appLockTimeoutValue = jsonData[APP_LOCK_TIMEOUT]?.toIntOrNull()
val homeBypassEnableValue = jsonData[HOME_BYPASS_ENABLED]?.lowercase()?.toBooleanStrictOrNull()
val appLockEnableValue = jsonData[APP_LOCK_ENABLED]?.lowercase()?.toBooleanStrictOrNull()
val appLockTimeoutValue = jsonData[APP_LOCK_TIMEOUT]?.toIntOrNull()
val homeBypassEnableValue = jsonData[HOME_BYPASS_ENABLED]?.lowercase()?.toBooleanStrictOrNull()
val invalid = (!appLockEnablePresent && !appLockTimeoutPresent && !homeBypassEnablePresent) ||
(appLockEnablePresent && appLockEnableValue == null) ||
(appLockTimeoutPresent && (appLockTimeoutValue == null || appLockTimeoutValue < 0)) ||
(homeBypassEnablePresent && homeBypassEnableValue == null)
val invalid = (!appLockEnablePresent && !appLockTimeoutPresent && !homeBypassEnablePresent) ||
(appLockEnablePresent && appLockEnableValue == null) ||
(appLockTimeoutPresent && (appLockTimeoutValue == null || appLockTimeoutValue < 0)) ||
(homeBypassEnablePresent && homeBypassEnableValue == null)
if (!invalid) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
if (!invalid) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Invalid app lock command received, posting notification to device"
@ -466,28 +447,24 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_WEBVIEW -> {
handleDeviceCommands(jsonData)
}
COMMAND_SCREEN_ON -> {
handleDeviceCommands(jsonData)
}
COMMAND_MEDIA -> {
if (!jsonData[MEDIA_COMMAND].isNullOrEmpty() && jsonData[MEDIA_COMMAND] in MEDIA_COMMANDS && !jsonData[MEDIA_PACKAGE_NAME].isNullOrEmpty()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_WEBVIEW -> {
handleDeviceCommands(jsonData)
}
COMMAND_SCREEN_ON -> {
handleDeviceCommands(jsonData)
}
COMMAND_MEDIA -> {
if (!jsonData[MEDIA_COMMAND].isNullOrEmpty() && jsonData[MEDIA_COMMAND] in MEDIA_COMMANDS && !jsonData[MEDIA_PACKAGE_NAME].isNullOrEmpty()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Posting notification to device as it does not support media commands"
)
sendNotification(jsonData)
}
}
} else {
mainScope.launch {
} else {
Log.d(
TAG,
"Invalid media command received, posting notification to device"
@ -495,13 +472,11 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_UPDATE_SENSORS -> SensorReceiver.updateAllSensors(context)
COMMAND_LAUNCH_APP -> {
if (!jsonData[PACKAGE_NAME].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_UPDATE_SENSORS -> SensorReceiver.updateAllSensors(context)
COMMAND_LAUNCH_APP -> {
if (!jsonData[PACKAGE_NAME].isNullOrEmpty()) {
handleDeviceCommands(jsonData)
} else {
Log.d(
TAG,
"Missing package name for app to launch, posting notification to device"
@ -509,57 +484,48 @@ class MessagingManager @Inject constructor(
sendNotification(jsonData)
}
}
}
COMMAND_PERSISTENT_CONNECTION -> {
val validPersistentTypes = WebsocketSetting.values().map { setting -> setting.name }
COMMAND_PERSISTENT_CONNECTION -> {
val validPersistentTypes = WebsocketSetting.values().map { setting -> setting.name }
when {
jsonData[PERSISTENT].isNullOrEmpty() -> {
mainScope.launch {
when {
jsonData[PERSISTENT].isNullOrEmpty() -> {
Log.d(
TAG,
"Missing persistent modifier, posting notification to device"
)
sendNotification(jsonData)
}
}
jsonData[PERSISTENT]!!.uppercase() !in validPersistentTypes -> {
mainScope.launch {
jsonData[PERSISTENT]!!.uppercase() !in validPersistentTypes -> {
Log.d(
TAG,
"Persistent modifier is not one of $validPersistentTypes"
)
sendNotification(jsonData)
}
else -> handleDeviceCommands(jsonData)
}
else -> handleDeviceCommands(jsonData)
}
}
TextToSpeechData.COMMAND_STOP_TTS -> stopTTS()
COMMAND_AUTO_SCREEN_BRIGHTNESS -> {
if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_AUTO_SCREEN_BRIGHTNESS -> {
if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) {
handleDeviceCommands(jsonData)
} else {
sendNotification(jsonData)
}
}
}
COMMAND_SCREEN_BRIGHTNESS_LEVEL, COMMAND_SCREEN_OFF_TIMEOUT -> {
if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null) {
handleDeviceCommands(jsonData)
} else {
mainScope.launch {
COMMAND_SCREEN_BRIGHTNESS_LEVEL, COMMAND_SCREEN_OFF_TIMEOUT -> {
if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null) {
handleDeviceCommands(jsonData)
} else {
sendNotification(jsonData)
}
}
else -> Log.d(TAG, "No command received")
}
else -> Log.d(TAG, "No command received")
}
}
else -> mainScope.launch {
Log.d(TAG, "Creating notification with following data: $jsonData")
sendNotification(jsonData, notificationId, now)
else -> {
Log.d(TAG, "Creating notification with following data: $jsonData")
sendNotification(jsonData, notificationId, now)
}
}
}
}

View file

@ -32,6 +32,7 @@ class ServerSettingsPresenterImpl @Inject constructor(
override fun getBoolean(key: String?, defValue: Boolean): Boolean = runBlocking {
when (key) {
"trust_server" -> serverManager.integrationRepository(serverId).isTrusted()
"app_lock" -> serverManager.authenticationRepository(serverId).isLockEnabledRaw()
"app_lock_home_bypass" -> serverManager.authenticationRepository(serverId).isLockHomeBypassEnabled()
else -> throw IllegalArgumentException("No boolean found by this key: $key")
@ -41,6 +42,7 @@ class ServerSettingsPresenterImpl @Inject constructor(
override fun putBoolean(key: String?, value: Boolean) {
mainScope.launch {
when (key) {
"trust_server" -> serverManager.integrationRepository(serverId).setTrusted(value)
"app_lock" -> serverManager.authenticationRepository(serverId).setLockEnabled(value)
"app_lock_home_bypass" -> serverManager.authenticationRepository(serverId).setLockHomeBypassEnabled(value)
else -> throw IllegalArgumentException("No boolean found by this key: $key")

View file

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@color/colorAccent" android:pathData="M15,9L9,9c-0.55,0 -1,0.45 -1,1v12c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1L16,10c0,-0.55 -0.45,-1 -1,-1zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM7.05,6.05l1.41,1.41C9.37,6.56 10.62,6 12,6s2.63,0.56 3.54,1.46l1.41,-1.41C15.68,4.78 13.93,4 12,4s-3.68,0.78 -4.95,2.05zM12,0C8.96,0 6.21,1.23 4.22,3.22l1.41,1.41C7.26,3.01 9.51,2 12,2s4.74,1.01 6.36,2.64l1.41,-1.41C17.79,1.23 15.04,0 12,0z"/>
</vector>

View file

@ -41,6 +41,12 @@
<PreferenceCategory
android:key="security_category"
android:title="@string/security">
<SwitchPreference
android:key="trust_server"
android:defaultValue="true"
android:icon="@drawable/ic_settings_remote"
android:title="@string/trust_server_title"
android:summary="@string/trust_server_summary"/>
<SwitchPreference
android:key="app_lock"
android:icon="@drawable/ic_lock"

View file

@ -21,6 +21,7 @@ class LaunchPresenterImpl @Inject constructor(
"${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})"
)
)
serverManager.integrationRepository(it.id).getConfig() // Update cached data
} catch (e: Exception) {
Log.e(TAG, "Issue updating Registration", e)
}

View file

@ -50,6 +50,10 @@ interface IntegrationRepository {
suspend fun registerSensor(sensorRegistration: SensorRegistration<Any>)
suspend fun updateSensors(sensors: Array<SensorRegistration<Any>>): Boolean
suspend fun isTrusted(): Boolean
suspend fun setTrusted(trusted: Boolean)
suspend fun shouldNotifySecurityWarning(): Boolean
suspend fun getConversation(speech: String): String?

View file

@ -56,6 +56,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
private const val PREF_CHECK_SENSOR_REGISTRATION_NEXT = "sensor_reg_last"
private const val PREF_SESSION_TIMEOUT = "session_timeout"
private const val PREF_SESSION_EXPIRE = "session_expire"
private const val PREF_TRUSTED = "trusted"
private const val PREF_SEC_WARNING_NEXT = "sec_warning_last"
private const val TAG = "IntegrationRepository"
private const val RATE_LIMIT_URL = BuildConfig.RATE_LIMIT_URL
@ -157,6 +158,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
localStorage.remove("${serverId}_$PREF_CHECK_SENSOR_REGISTRATION_NEXT")
localStorage.remove("${serverId}_$PREF_SESSION_TIMEOUT")
localStorage.remove("${serverId}_$PREF_SESSION_EXPIRE")
localStorage.remove("${serverId}_$PREF_TRUSTED")
localStorage.remove("${serverId}_$PREF_SEC_WARNING_NEXT")
// app version and push token is device-specific
}
@ -393,6 +395,12 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
private suspend fun getSessionExpireMillis(): Long =
localStorage.getLong("${serverId}_$PREF_SESSION_EXPIRE") ?: 0
override suspend fun isTrusted(): Boolean =
localStorage.getBooleanOrNull("${serverId}_$PREF_TRUSTED") ?: true
override suspend fun setTrusted(trusted: Boolean) =
localStorage.putBoolean("${serverId}_$PREF_TRUSTED", trusted)
override suspend fun getNotificationRateLimits(): RateLimitResponse {
val pushToken = localStorage.getString(PREF_PUSH_TOKEN) ?: ""
val requestBody = RateLimitRequest(pushToken)

View file

@ -207,19 +207,22 @@ abstract class SensorReceiverBase : BroadcastReceiver() {
): Boolean {
val currentHAversion = serverManager.integrationRepository(server.id).getHomeAssistantVersion()
val supportsDisabledSensors = serverManager.integrationRepository(server.id).isHomeAssistantVersionAtLeast(2022, 6, 0)
val coreSensorStatus: Map<String, Boolean>? = if (supportsDisabledSensors) {
try {
val config = serverManager.integrationRepository(server.id).getConfig().entities
config
?.filter { it.value["disabled"] != null }
?.mapValues { !(it.value["disabled"] as Boolean) } // Map to sensor id -> enabled
} catch (e: Exception) {
Log.e(tag, "Error while getting core config to sync sensor status", e)
val serverIsTrusted = serverManager.integrationRepository(server.id).isTrusted()
val coreSensorStatus: Map<String, Boolean>? =
if (supportsDisabledSensors && (serverIsTrusted || (sensorDao.getEnabledCount() ?: 0) > 0)) {
try {
val config = serverManager.integrationRepository(server.id).getConfig().entities
config
?.filter { it.value["disabled"] != null }
?.mapValues { !(it.value["disabled"] as Boolean) } // Map to sensor id -> enabled
} catch (e: Exception) {
Log.e(tag, "Error while getting core config to sync sensor status", e)
null
}
} else {
// Cannot sync disabled, or all sensors disabled and server changes aren't trusted
null
}
} else {
null
}
var serverIsReachable = true
val enabledRegistrations = mutableListOf<SensorRegistration<Any>>()
@ -268,9 +271,12 @@ abstract class SensorReceiverBase : BroadcastReceiver() {
sensorCoreEnabled != sensor.registered
) {
// 2. Try updating the sensor enabled state to match core state when it's different from
// the app, if the sensor can be registered and on core >= 2022.6
// the app, if the sensor can be registered, on core >= 2022.6 and server trusted.
// If the server isn't trusted, update registered state to match app.
try {
if (sensorCoreEnabled) { // App disabled, should enable
if (!serverIsTrusted) { // Core changed, but app doesn't trust server so 'override'
registerSensor(context, serverManager, fullSensor, basicSensor)
} else if (sensorCoreEnabled) { // App disabled, should enable
if (manager.checkPermission(context.applicationContext, basicSensor.id)) {
sensor.enabled = true
sensor.registered = true

View file

@ -833,6 +833,8 @@
<string name="tile_updated">Tile Data updated</string>
<string name="tiles">Tiles</string>
<string name="toast_message">%1$s was selected</string>
<string name="trust_server_title">Remotely control app &amp; device</string>
<string name="trust_server_summary">Manage enabled sensors and use notification commands from this server</string>
<string name="tts_error">Unable to process notification \"%1$s\" as text to speech.</string>
<string name="tts_no_text">Please set the text for text to speech to process</string>
<string name="unable_to_register">Unable to Register Application</string>

View file

@ -26,6 +26,7 @@ import io.homeassistant.companion.android.database.sensor.SensorDao
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.json.JSONObject
import javax.inject.Inject
@ -49,25 +50,29 @@ class MessagingManager @Inject constructor(
val jsonObject = jsonData?.let { JSONObject(it) }
val serverId = jsonData?.get(NotificationData.WEBHOOK_ID)?.let {
serverManager.getServer(webhookId = it)?.id
}
} ?: ServerManager.SERVER_ID_ACTIVE
val notificationRow =
NotificationItem(0, now, notificationData[NotificationData.MESSAGE].toString(), jsonObject.toString(), source, serverId)
notificationDao.add(notificationRow)
when (notificationData[NotificationData.MESSAGE]) {
DeviceCommandData.COMMAND_BEACON_MONITOR -> {
if (!commandBeaconMonitor(context, notificationData)) {
sendNotification(notificationData, now)
mainScope.launch {
val allowCommands = serverManager.integrationRepository(serverId).isTrusted()
val message = notificationData[NotificationData.MESSAGE]
when {
message == DeviceCommandData.COMMAND_BEACON_MONITOR && allowCommands -> {
if (!commandBeaconMonitor(context, notificationData)) {
sendNotification(notificationData, now)
}
}
}
DeviceCommandData.COMMAND_BLE_TRANSMITTER -> {
if (!commandBleTransmitter(context, notificationData, sensorDao, mainScope)) {
sendNotification(notificationData)
message == DeviceCommandData.COMMAND_BLE_TRANSMITTER && allowCommands -> {
if (!commandBleTransmitter(context, notificationData, sensorDao, mainScope)) {
sendNotification(notificationData)
}
}
message == TextToSpeechData.TTS -> speakText(context, notificationData)
message == TextToSpeechData.COMMAND_STOP_TTS -> stopTTS()
else -> sendNotification(notificationData, now)
}
TextToSpeechData.TTS -> speakText(context, notificationData)
TextToSpeechData.COMMAND_STOP_TTS -> stopTTS()
else -> sendNotification(notificationData, now)
}
}