From 7c940d209a89310d55266ba008901aa292723ab5 Mon Sep 17 00:00:00 2001 From: Douile <25043847+Douile@users.noreply.github.com> Date: Mon, 22 Aug 2022 16:19:59 +0100 Subject: [PATCH 01/10] Show warning in dialog when using default encryption key --- .../com/geeksville/mesh/ui/ChannelFragment.kt | 85 +++++++++++-------- app/src/main/res/values/strings.xml | 1 + 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt index efebd43dd..f38ad009b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt @@ -304,49 +304,60 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { } } else { // User just locked it, we should warn and then apply changes to radio - MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.change_channel) - .setMessage(R.string.are_you_sure_channel) - .setNeutralButton(R.string.cancel) { _, _ -> - setGUIfromModel() + + model.channels.value?.primaryChannel?.let { oldPrimary -> + var newSettings = oldPrimary.settings.toBuilder() + val newName = binding.channelNameEdit.text.toString().trim() + + // Find the new modem config + val selectedModemPresetString = + binding.filledExposedDropdown.editableText.toString() + var newModemPreset = getModemPreset(selectedModemPresetString) + if (newModemPreset == ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED) // Huh? didn't find it - keep same + newModemPreset = oldPrimary.loraConfig.modemPreset + + // Generate a new AES256 key if the user changes channel name or the name is non-default and the settings changed + val shouldUseRandomKey = + newName != originalName || (newName.isNotEmpty() && newModemPreset != oldPrimary.loraConfig.modemPreset) + if (shouldUseRandomKey) { + + // Install a new customized channel + debug("ASSIGNING NEW AES256 KEY") + val random = SecureRandom() + val bytes = ByteArray(32) + random.nextBytes(bytes) + newSettings.name = newName.take(11) // proto max_size:12 + newSettings.psk = ByteString.copyFrom(bytes) + } else { + debug("Switching back to default channel") + newSettings = Channel.default.settings.toBuilder() } - .setPositiveButton(getString(R.string.accept)) { _, _ -> - // Generate a new channel with only the changes the user can change in the GUI - model.channels.value?.primaryChannel?.let { oldPrimary -> - var newSettings = oldPrimary.settings.toBuilder() - val newName = binding.channelNameEdit.text.toString().trim() - // Find the new modem config - val selectedModemPresetString = - binding.filledExposedDropdown.editableText.toString() - var newModemPreset = getModemPreset(selectedModemPresetString) - if (newModemPreset == ConfigProtos.Config.LoRaConfig.ModemPreset.UNRECOGNIZED) // Huh? didn't find it - keep same - newModemPreset = oldPrimary.loraConfig.modemPreset + // No matter what apply the speed selection from the user + val newLoRaConfig = ConfigProtos.Config.LoRaConfig.newBuilder() + .setRegion(model.region) + .setModemPreset(newModemPreset) - // Generate a new AES256 key if the user changes channel name or the name is non-default and the settings changed - if (newName != originalName || (newName.isNotEmpty() && newModemPreset != oldPrimary.loraConfig.modemPreset)) { - // Install a new customized channel - debug("ASSIGNING NEW AES256 KEY") - val random = SecureRandom() - val bytes = ByteArray(32) - random.nextBytes(bytes) - newSettings.name = newName.take(11) // proto max_size:12 - newSettings.psk = ByteString.copyFrom(bytes) - } else { - debug("Switching back to default channel") - newSettings = Channel.default.settings.toBuilder() + MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.change_channel) + .setMessage(buildString { + append(getString(R.string.are_you_sure_channel)) + if (!shouldUseRandomKey) { + append("\n\n") + append(getString(R.string.warning_default_channel)) } - - // No matter what apply the speed selection from the user - val newLoRaConfig = ConfigProtos.Config.LoRaConfig.newBuilder() - .setRegion(model.region) - .setModemPreset(newModemPreset) - - installSettings(newSettings.build(),newLoRaConfig.build()) + }) + .setNeutralButton(R.string.cancel) { _, _ -> + setGUIfromModel() } - } - .show() + .setPositiveButton(getString(R.string.accept)) { _, _ -> + // Generate a new channel with only the changes the user can change in the GUI + + installSettings(newSettings.build(), newLoRaConfig.build()) + } + .show() + } } onEditingChanged() // update GUI on what user is allowed to edit/share diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 88a99668b..389abfd46 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,4 +155,5 @@ Message Append to message Instantly send + As you have not changed the channel name you are using the default encryption key (any Meshtastic user can read your messages). From f8cec34862dc031e2bf5dd637c577d409ef4ec17 Mon Sep 17 00:00:00 2001 From: Tom <25043847+Douile@users.noreply.github.com> Date: Tue, 23 Aug 2022 10:44:34 +0000 Subject: [PATCH 02/10] Improve warning message Improve wording and add channel name to the default psk warning Co-authored-by: Andre K --- .../com/geeksville/mesh/ui/ChannelFragment.kt | 16 +++++++++------- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt index f38ad009b..bd4fe6a35 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/ChannelFragment.kt @@ -338,16 +338,18 @@ class ChannelFragment : ScreenFragment("Channel"), Logging { .setRegion(model.region) .setModemPreset(newModemPreset) + val humanName = Channel(newSettings.build(), newLoRaConfig.build()).humanName + binding.channelNameEdit.setText(humanName) + + val message = buildString { + append(getString(R.string.are_you_sure_channel)) + if (!shouldUseRandomKey) + append("\n\n" + getString(R.string.warning_default_psk).format(humanName)) + } MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.change_channel) - .setMessage(buildString { - append(getString(R.string.are_you_sure_channel)) - if (!shouldUseRandomKey) { - append("\n\n") - append(getString(R.string.warning_default_channel)) - } - }) + .setMessage(message) .setNeutralButton(R.string.cancel) { _, _ -> setGUIfromModel() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 389abfd46..4cbea2cab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,5 +155,5 @@ Message Append to message Instantly send - As you have not changed the channel name you are using the default encryption key (any Meshtastic user can read your messages). + Empty channel names use the default encryption key (any device on %s can read your messages). From 325ef8e1b66a2d25dd235e4e1fdeafa1fe486c63 Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 08:23:57 -0300 Subject: [PATCH 03/10] add bluetooth config proto --- .../mesh/repository/datastore/LocalConfigRepository.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/geeksville/mesh/repository/datastore/LocalConfigRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/datastore/LocalConfigRepository.kt index 972e4dfc0..429125692 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/datastore/LocalConfigRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/datastore/LocalConfigRepository.kt @@ -61,6 +61,7 @@ class LocalConfigRepository @Inject constructor( if (config.hasWifi()) setWifiConfig(config.wifi) if (config.hasDisplay()) setDisplayConfig(config.display) if (config.hasLora()) setLoraConfig(config.lora) + if (config.hasBluetooth()) setBluetoothConfig(config.bluetooth) } private suspend fun setDeviceConfig(config: ConfigProtos.Config.DeviceConfig) { @@ -99,6 +100,12 @@ class LocalConfigRepository @Inject constructor( } } + private suspend fun setBluetoothConfig(config: ConfigProtos.Config.BluetoothConfig) { + localConfigStore.updateData { preference -> + preference.toBuilder().setBluetooth(config).build() + } + } + suspend fun fetchInitialLocalConfig() = localConfigStore.data.first() } From a6b4e400a68cee904b4daf33ce4bd4356dd13a6a Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 08:26:29 -0300 Subject: [PATCH 04/10] update release notes metadata --- app/src/main/play/release-notes/en-US/alpha.txt | 2 +- app/src/main/play/release-notes/en-US/beta.txt | 2 +- app/src/main/play/release-notes/en-US/production.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/play/release-notes/en-US/alpha.txt b/app/src/main/play/release-notes/en-US/alpha.txt index e7baf1655..e4da04080 100644 --- a/app/src/main/play/release-notes/en-US/alpha.txt +++ b/app/src/main/play/release-notes/en-US/alpha.txt @@ -1 +1 @@ -Lots of improvements - see meshtastic.discourse.group +For more information visit meshtastic.org. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at meshtastic.discourse.group and we'll help. diff --git a/app/src/main/play/release-notes/en-US/beta.txt b/app/src/main/play/release-notes/en-US/beta.txt index e7baf1655..e4da04080 100644 --- a/app/src/main/play/release-notes/en-US/beta.txt +++ b/app/src/main/play/release-notes/en-US/beta.txt @@ -1 +1 @@ -Lots of improvements - see meshtastic.discourse.group +For more information visit meshtastic.org. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at meshtastic.discourse.group and we'll help. diff --git a/app/src/main/play/release-notes/en-US/production.txt b/app/src/main/play/release-notes/en-US/production.txt index e7baf1655..e4da04080 100644 --- a/app/src/main/play/release-notes/en-US/production.txt +++ b/app/src/main/play/release-notes/en-US/production.txt @@ -1 +1 @@ -Lots of improvements - see meshtastic.discourse.group +For more information visit meshtastic.org. This application is made by volunteers. We are friendly and actively respond to forum posts with any questions you have. Post at meshtastic.discourse.group and we'll help. From 9c6384a2fe30132ad88d2fb19b78f35529dbe13a Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 18:06:02 -0300 Subject: [PATCH 05/10] add debug msg to shutdown and reboot --- .../java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt index 6d6bff5de..53faed41b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt @@ -115,6 +115,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { .setNeutralButton(R.string.cancel) { _, _ -> } .setPositiveButton(getString(R.string.okay)) { _, _ -> + debug("User clicked requestShutdown") model.requestShutdown() } .show() @@ -126,6 +127,7 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging { .setNeutralButton(R.string.cancel) { _, _ -> } .setPositiveButton(getString(R.string.okay)) { _, _ -> + debug("User clicked requestReboot") model.requestReboot() } .show() From cf827aefafcb7962cb953b893fb4676665442d23 Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 18:08:43 -0300 Subject: [PATCH 06/10] rip ota --- .github/workflows/release.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f8787afb..e4703ce93 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,21 +60,21 @@ jobs: rm ./app/src/main/res/values/curfirmwareversion.xml echo -e "\n ${{ env.CUR_FIRMWARE_VERSION }}\n ${{ env.SHORT_FIRMWARE_VERSION }}\n" > ./app/src/main/res/values/curfirmwareversion.xml - - name: Fetch firmware release - uses: dsaltares/fetch-gh-release-asset@master - with: - repo: meshtastic/Meshtastic-device - file: firmware-${{ env.CUR_FIRMWARE_VERSION }}.zip - version: tags/${{ steps.firmware_version.outputs.tag }} - target: firmware.zip - token: ${{ secrets.GITHUB_TOKEN }} +# - name: Fetch firmware release +# uses: dsaltares/fetch-gh-release-asset@master +# with: +# repo: meshtastic/Meshtastic-device +# file: firmware-${{ env.CUR_FIRMWARE_VERSION }}.zip +# version: tags/${{ steps.firmware_version.outputs.tag }} +# target: firmware.zip +# token: ${{ secrets.GITHUB_TOKEN }} - - name: Unzip firmware into assets/firmware - run: | - rm -rf ./app/src/main/assets/firmware - mkdir -p ./app/src/main/assets/firmware - unzip -qq ./firmware.zip 'littlefs-*.bin' 'firmware-heltec*.bin' 'firmware-tbeam*.bin' 'firmware-tlora*.bin' 'firmware-nano*.bin' -d ./app/src/main/assets/firmware - rm ./firmware.zip +# - name: Unzip firmware into assets/firmware +# run: | +# rm -rf ./app/src/main/assets/firmware +# mkdir -p ./app/src/main/assets/firmware +# unzip -qq ./firmware.zip 'littlefs-*.bin' 'firmware-heltec*.bin' 'firmware-tbeam*.bin' 'firmware-tlora*.bin' 'firmware-nano*.bin' -d ./app/src/main/assets/firmware +# rm ./firmware.zip - name: Validate Gradle wrapper uses: gradle/wrapper-validation-action@v1 From 69f311e133be8ffcb29e1af1789674b69dead709 Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 21:39:08 -0300 Subject: [PATCH 07/10] clean up and reformat --- app/src/main/java/com/geeksville/mesh/BaseActivity.kt | 10 +++++----- app/src/main/java/com/geeksville/mesh/MainActivity.kt | 3 +-- .../com/geeksville/mesh/android/ContextServices.kt | 4 +--- app/src/main/java/com/geeksville/mesh/model/UIState.kt | 9 +++------ 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/BaseActivity.kt b/app/src/main/java/com/geeksville/mesh/BaseActivity.kt index 1556dbd05..205a20b25 100644 --- a/app/src/main/java/com/geeksville/mesh/BaseActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/BaseActivity.kt @@ -37,12 +37,12 @@ open class BaseActivity: AppCompatActivity(), Logging { } } - private fun createLocale(language: String):Locale { - var langArray = language.split("_") - if (langArray.size == 2) { - return Locale(langArray[0], langArray[1]); + private fun createLocale(language: String): Locale { + val langArray = language.split("_") + return if (langArray.size == 2) { + Locale(langArray[0], langArray[1]) } else { - return Locale(langArray[0]); + Locale(langArray[0]) } } diff --git a/app/src/main/java/com/geeksville/mesh/MainActivity.kt b/app/src/main/java/com/geeksville/mesh/MainActivity.kt index e38b7d5d7..8f0263508 100644 --- a/app/src/main/java/com/geeksville/mesh/MainActivity.kt +++ b/app/src/main/java/com/geeksville/mesh/MainActivity.kt @@ -409,11 +409,10 @@ class MainActivity : BaseActivity(), Logging, installSplashScreen() super.onCreate(savedInstanceState) - if (preferences.getBoolean("app_intro_completed", false) == false) { + if (!preferences.getBoolean("app_intro_completed", false)) { startActivity(Intent(this, AppIntroduction::class.java)) } - binding = ActivityMainBinding.inflate(layoutInflater) val prefs = UIViewModel.getPreferences(this) diff --git a/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt b/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt index 3a9ddf10f..6915ef4a5 100644 --- a/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt +++ b/app/src/main/java/com/geeksville/mesh/android/ContextServices.kt @@ -1,7 +1,6 @@ package com.geeksville.mesh.android import android.Manifest -import android.annotation.SuppressLint import android.app.NotificationManager import android.bluetooth.BluetoothManager import android.companion.CompanionDeviceManager @@ -19,7 +18,6 @@ import com.geeksville.mesh.MainActivity val Context.bluetoothManager: BluetoothManager? get() = getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager? val Context.deviceManager: CompanionDeviceManager? - @SuppressLint("InlinedApi") get() { if (GeeksvilleApplication.currentActivity is MainActivity) { val activity = GeeksvilleApplication.currentActivity @@ -47,7 +45,7 @@ fun Context.hasGps(): Boolean = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS) /** - * return app install source (sideload = null) + * return app install source (play store = com.android.vending) */ fun Context.installSource(): String? { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index daf27fa2d..00664b17b 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -71,13 +71,10 @@ class UIViewModel @Inject constructor( private val _allPacketState = MutableStateFlow>(emptyList()) val allPackets: StateFlow> = _allPacketState - private val _localConfig = MutableLiveData() - val localConfig: LiveData get() = _localConfig + private val _localConfig = MutableLiveData() + val localConfig: LiveData get() = _localConfig - private val _quickChatActions = - MutableStateFlow>( - emptyList() - ) + private val _quickChatActions = MutableStateFlow>(emptyList()) val quickChatActions: StateFlow> = _quickChatActions init { From d5c32407ad251a2ca1532502682c308c5a9f1885 Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 21:51:27 -0300 Subject: [PATCH 08/10] add connection feedback --- .../java/com/geeksville/mesh/ui/SettingsFragment.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt index 3326883c6..dff076719 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/SettingsFragment.kt @@ -281,7 +281,17 @@ class SettingsFragment : ScreenFragment("Settings"), Logging { } model.localConfig.observe(viewLifecycleOwner) { - updateNodeInfo() + if (!model.isConnected()) { + val configCount = it.allFields.size + binding.scanStatusText.text = "Device config ($configCount / 7)" + } else updateNodeInfo() + } + + model.channels.observe(viewLifecycleOwner) { + if (!model.isConnected()) { + val channelCount = it?.protobuf?.settingsCount ?: 0 + binding.scanStatusText.text = "Channels ($channelCount / 8)" + } } // Also watch myNodeInfo because it might change later From 92d6be9d43d4c4dd4503a9f8bb513b8104d264e1 Mon Sep 17 00:00:00 2001 From: andrekir Date: Tue, 23 Aug 2022 21:52:29 -0300 Subject: [PATCH 09/10] 1.3.39 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b10034946..eac5e97d0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,8 +43,8 @@ android { applicationId "com.geeksville.mesh" minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) targetSdkVersion 30 // 30 can't work until an explicit location permissions dialog is added - versionCode 20338 // format is Mmmss (where M is 1+the numeric major number - versionName "1.3.38" + versionCode 20339 // format is Mmmss (where M is 1+the numeric major number + versionName "1.3.39" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // per https://developer.android.com/studio/write/vector-asset-studio From c567df135521a1119dfd83c759e51a5b831b8c49 Mon Sep 17 00:00:00 2001 From: Andre K Date: Tue, 23 Aug 2022 22:14:59 -0300 Subject: [PATCH 10/10] mock firmware assets for release --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e4703ce93..7ff5c0925 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,6 +76,11 @@ jobs: # unzip -qq ./firmware.zip 'littlefs-*.bin' 'firmware-heltec*.bin' 'firmware-tbeam*.bin' 'firmware-tlora*.bin' 'firmware-nano*.bin' -d ./app/src/main/assets/firmware # rm ./firmware.zip + - name: Mock firmware assets for release + run: | + rm -rf ./app/src/main/assets/firmware + mkdir -p ./app/src/main/assets/firmware + - name: Validate Gradle wrapper uses: gradle/wrapper-validation-action@v1