Key verification flow on BaseUI (#7240)

This commit is contained in:
Jonathan Bennett 2025-07-10 09:45:36 -05:00 committed by GitHub
parent a7e516d6f6
commit 0795b21c2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 211 additions and 126 deletions

View File

@ -171,7 +171,7 @@ void Screen::showOverlayBanner(BannerOverlayOptions banner_overlay_options)
}
// Called to trigger a banner with custom message and duration
void Screen::showNodePicker(const char *message, uint32_t durationMs, std::function<void(int)> bannerCallback)
void Screen::showNodePicker(const char *message, uint32_t durationMs, std::function<void(uint32_t)> bannerCallback)
{
#ifdef USE_EINK
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
@ -196,7 +196,6 @@ void Screen::showNodePicker(const char *message, uint32_t durationMs, std::funct
void Screen::showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits,
std::function<void(uint32_t)> bannerCallback)
{
LOG_WARN("Show Number Picker");
#ifdef USE_EINK
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Skip full refresh for all overlay menus
#endif
@ -1330,7 +1329,7 @@ int Screen::handleInputEvent(const InputEvent *event)
setFastFramerate(); // Draw ASAP
#endif
if (NotificationRenderer::isOverlayBannerShowing()) {
NotificationRenderer::inEvent = event->inputEvent;
NotificationRenderer::inEvent = *event;
static OverlayCallback overlays[] = {graphics::UIRenderer::drawNavigationBar, NotificationRenderer::drawBannercallback};
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
setFastFramerate(); // Draw ASAP

View File

@ -92,6 +92,7 @@ class Screen
#include "commands.h"
#include "concurrency/LockGuard.h"
#include "concurrency/OSThread.h"
#include "graphics/draw/MenuHandler.h"
#include "input/InputBroker.h"
#include "mesh/MeshModule.h"
#include "modules/AdminModule.h"
@ -308,9 +309,15 @@ class Screen : public concurrency::OSThread
void showSimpleBanner(const char *message, uint32_t durationMs = 0);
void showOverlayBanner(BannerOverlayOptions);
void showNodePicker(const char *message, uint32_t durationMs, std::function<void(int)> bannerCallback);
void showNodePicker(const char *message, uint32_t durationMs, std::function<void(uint32_t)> bannerCallback);
void showNumberPicker(const char *message, uint32_t durationMs, uint8_t digits, std::function<void(uint32_t)> bannerCallback);
void requestMenu(graphics::menuHandler::screenMenus menuToShow)
{
graphics::menuHandler::menuQueue = menuToShow;
runNow();
}
void startFirmwareUpdateScreen()
{
ScreenCmd cmd;

View File

@ -13,6 +13,7 @@
#include "main.h"
#include "modules/AdminModule.h"
#include "modules/CannedMessageModule.h"
#include "modules/KeyVerificationModule.h"
extern uint16_t TFT_MESH;
@ -237,27 +238,25 @@ void menuHandler::clockMenu()
void menuHandler::messageResponseMenu()
{
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3, Aloud = 4, enumEnd = 5 };
static const char *optionsArray[enumEnd] = {"Back", "Dismiss", "Reply via Preset"};
static int optionsEnumArray[enumEnd] = {Back, Dismiss, Preset};
int options = 3;
static const char **optionsArrayPtr;
int options;
enum optionsNumbers { Back = 0, Dismiss = 1, Preset = 2, Freetext = 3 };
if (kb_found) {
static const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext"};
optionsArrayPtr = optionsArray;
options = 4;
} else {
static const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset"};
optionsArrayPtr = optionsArray;
options = 3;
optionsArray[options] = "Reply via Freetext";
optionsEnumArray[options++] = Freetext;
}
#ifdef HAS_I2S
static const char *optionsArray[] = {"Back", "Dismiss", "Reply via Preset", "Reply via Freetext", "Read Aloud"};
optionsArrayPtr = optionsArray;
options = 5;
optionsArray[options] = "Read Aloud";
optionsEnumArray[options++] = Aloud;
#endif
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Message Action";
bannerOptions.optionsArrayPtr = optionsArrayPtr;
bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsEnumPtr = optionsEnumArray;
bannerOptions.optionsCount = options;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == Dismiss) {
@ -276,7 +275,7 @@ void menuHandler::messageResponseMenu()
}
}
#ifdef HAS_I2S
else if (selected == 4) {
else if (selected == Aloud) {
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
const char *msg = reinterpret_cast<const char *>(mp.decoded.payload.bytes);
@ -289,10 +288,10 @@ void menuHandler::messageResponseMenu()
void menuHandler::homeBaseMenu()
{
enum optionsNumbers { Back, Backlight, Position, Preset, Freetext, Bluetooth, Sleep };
enum optionsNumbers { Back, Backlight, Position, Preset, Freetext, Bluetooth, Sleep, enumEnd };
static const char *optionsArray[6] = {"Back"};
static int optionsEnumArray[6] = {Back};
static const char *optionsArray[enumEnd] = {"Back"};
static int optionsEnumArray[enumEnd] = {Back};
int options = 1;
#ifdef PIN_EINK_EN
@ -354,9 +353,9 @@ void menuHandler::systemBaseMenu()
hasSupportBrightness = true;
#endif
enum optionsNumbers { Back, Beeps, Brightness, Reboot, Color, MUI, Test };
static const char *optionsArray[7] = {"Back"};
static int optionsEnumArray[7] = {Back};
enum optionsNumbers { Back, Beeps, Brightness, Reboot, Color, MUI, Test, enumEnd };
static const char *optionsArray[enumEnd] = {"Back"};
static int optionsEnumArray[enumEnd] = {Back};
int options = 1;
optionsArray[options] = "Reboot";
@ -419,21 +418,22 @@ void menuHandler::systemBaseMenu()
void menuHandler::favoriteBaseMenu()
{
int options;
static const char **optionsArrayPtr;
enum optionsNumbers { Back, Preset, Freetext, Remove, enumEnd };
static const char *optionsArray[enumEnd] = {"Back", "New Preset Msg"};
static int optionsEnumArray[enumEnd] = {Back, Preset};
int options = 2;
if (kb_found) {
static const char *optionsArray[] = {"Back", "New Preset Msg", "New Freetext Msg", "Remove Favorite"};
optionsArrayPtr = optionsArray;
options = 4;
} else {
static const char *optionsArray[] = {"Back", "New Preset Msg", "Remove Favorite"};
optionsArrayPtr = optionsArray;
options = 3;
optionsArray[options] = "New Freetext Msg";
optionsEnumArray[options++] = Freetext;
}
optionsArray[options] = "Remove Favorite";
optionsEnumArray[options++] = Remove;
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Favorites Action";
bannerOptions.optionsArrayPtr = optionsArrayPtr;
bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsEnumPtr = optionsEnumArray;
bannerOptions.optionsCount = options;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) {
@ -450,34 +450,29 @@ void menuHandler::favoriteBaseMenu()
void menuHandler::positionBaseMenu()
{
int options;
static const char **optionsArrayPtr;
static const char *optionsArray[] = {"Back", "GPS Toggle", "Compass"};
static const char *optionsArrayCalibrate[] = {"Back", "GPS Toggle", "Compass", "Compass Calibrate"};
enum optionsNumbers { Back, GPSToggle, CompassMenu, CompassCalibrate, enumEnd };
static const char *optionsArray[enumEnd] = {"Back", "GPS Toggle", "Compass"};
static int optionsEnumArray[enumEnd] = {Back, GPSToggle, CompassMenu};
int options = 3;
if (accelerometerThread) {
optionsArrayPtr = optionsArrayCalibrate;
options = 4;
} else {
optionsArrayPtr = optionsArray;
options = 3;
optionsArray[options] = "Compass Calibrate";
optionsEnumArray[options++] = CompassCalibrate;
}
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Position Action";
bannerOptions.optionsArrayPtr = optionsArrayPtr;
bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsEnumPtr = optionsEnumArray;
bannerOptions.optionsCount = options;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) {
#if MESHTASTIC_EXCLUDE_GPS
menuQueue = menu_none;
#else
if (selected == GPSToggle) {
menuQueue = gps_toggle_menu;
screen->runNow();
#endif
} else if (selected == 2) {
} else if (selected == CompassMenu) {
menuQueue = compass_point_north_menu;
screen->runNow();
} else if (selected == 3) {
} else if (selected == CompassCalibrate) {
accelerometerThread->calibrate(30);
}
};
@ -486,16 +481,20 @@ void menuHandler::positionBaseMenu()
void menuHandler::nodeListMenu()
{
static const char *optionsArray[] = {"Back", "Add Favorite", "Reset NodeDB"};
enum optionsNumbers { Back, Favorite, Verify, Reset };
static const char *optionsArray[] = {"Back", "Add Favorite", "Key Verification", "Reset NodeDB"};
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Node Action";
bannerOptions.optionsArrayPtr = optionsArray;
bannerOptions.optionsCount = 3;
bannerOptions.optionsCount = 4;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) {
if (selected == Favorite) {
menuQueue = add_favorite;
screen->runNow();
} else if (selected == 2) {
} else if (selected == Verify) {
menuQueue = key_verification_init;
screen->runNow();
} else if (selected == Reset) {
menuQueue = reset_node_db_menu;
screen->runNow();
}
@ -523,6 +522,7 @@ void menuHandler::resetNodeDBMenu()
void menuHandler::compassNorthMenu()
{
enum optionsNumbers { Back, Dynamic, Fixed, Freeze };
static const char *optionsArray[] = {"Back", "Dynamic", "Fixed Ring", "Freeze Heading"};
BannerOverlayOptions bannerOptions;
bannerOptions.message = "North Directions?";
@ -530,28 +530,28 @@ void menuHandler::compassNorthMenu()
bannerOptions.optionsCount = 4;
bannerOptions.InitialSelected = uiconfig.compass_mode + 1;
bannerOptions.bannerCallback = [](int selected) -> void {
if (selected == 1) {
if (selected == Dynamic) {
if (uiconfig.compass_mode != meshtastic_CompassMode_DYNAMIC) {
uiconfig.compass_mode = meshtastic_CompassMode_DYNAMIC;
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg,
&uiconfig);
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
}
} else if (selected == 2) {
} else if (selected == Fixed) {
if (uiconfig.compass_mode != meshtastic_CompassMode_FIXED_RING) {
uiconfig.compass_mode = meshtastic_CompassMode_FIXED_RING;
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg,
&uiconfig);
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
}
} else if (selected == 3) {
} else if (selected == Freeze) {
if (uiconfig.compass_mode != meshtastic_CompassMode_FREEZE_HEADING) {
uiconfig.compass_mode = meshtastic_CompassMode_FREEZE_HEADING;
nodeDB->saveProto("/prefs/uiconfig.proto", meshtastic_DeviceUIConfig_size, &meshtastic_DeviceUIConfig_msg,
&uiconfig);
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
}
} else if (selected == 0) {
} else if (selected == Back) {
menuQueue = position_base_menu;
screen->runNow();
}
@ -562,6 +562,7 @@ void menuHandler::compassNorthMenu()
#if !MESHTASTIC_EXCLUDE_GPS
void menuHandler::GPSToggleMenu()
{
static const char *optionsArray[] = {"Back", "Enabled", "Disabled"};
BannerOverlayOptions bannerOptions;
bannerOptions.message = "Toggle GPS";
@ -796,7 +797,7 @@ void menuHandler::rebootMenu()
void menuHandler::addFavoriteMenu()
{
screen->showNodePicker("Node To Favorite", 30000, [](int nodenum) -> void {
screen->showNodePicker("Node To Favorite", 30000, [](uint32_t nodenum) -> void {
LOG_WARN("Nodenum: %u", nodenum);
nodeDB->set_favorite(true, nodenum);
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
@ -887,6 +888,37 @@ void menuHandler::wifiToggleMenu()
screen->showOverlayBanner(bannerOptions);
}
void menuHandler::keyVerificationInitMenu()
{
screen->showNodePicker("Node to Verify", 30000,
[](uint32_t selected) -> void { keyVerificationModule->sendInitialRequest(selected); });
}
void menuHandler::keyVerificationFinalPrompt()
{
char message[40] = {0};
memset(message, 0, sizeof(message));
sprintf(message, "Verification: \n");
keyVerificationModule->generateVerificationCode(message + 15); // send the toPhone packet
if (screen) {
static const char *optionsArray[] = {"Reject", "Accept"};
graphics::BannerOverlayOptions options;
options.message = message;
options.durationMs = 30000;
options.optionsArrayPtr = optionsArray;
options.optionsCount = 2;
options.notificationType = graphics::notificationTypeEnum::selection_picker;
options.bannerCallback = [=](int selected) {
if (selected == 1) {
auto remoteNodePtr = nodeDB->getMeshNode(keyVerificationModule->getCurrentRemoteNode());
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
}
};
screen->showOverlayBanner(options);
}
}
void menuHandler::handleMenuSwitch(OLEDDisplay *display)
{
if (menuQueue != menu_none)
@ -953,9 +985,18 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
case wifi_toggle_menu:
wifiToggleMenu();
break;
case key_verification_init:
keyVerificationInitMenu();
break;
case key_verification_final_prompt:
keyVerificationFinalPrompt();
break;
case bluetooth_toggle_menu:
BluetoothToggleMenu();
break;
case throttle_message:
screen->showSimpleBanner("Too Many Attempts\nTry again in 60 seconds.", 5000);
break;
}
menuQueue = menu_none;
}

View File

@ -1,3 +1,5 @@
#pragma once
#if HAS_SCREEN
#include "configuration.h"
namespace graphics
{
@ -26,7 +28,10 @@ class menuHandler
test_menu,
number_test,
wifi_toggle_menu,
bluetooth_toggle_menu
key_verification_init,
key_verification_final_prompt,
bluetooth_toggle_menu,
throttle_message
};
static screenMenus menuQueue;
@ -56,7 +61,10 @@ class menuHandler
static void numberTest();
static void wifiBaseMenu();
static void wifiToggleMenu();
static void keyVerificationInitMenu();
static void keyVerificationFinalPrompt();
static void BluetoothToggleMenu();
};
} // namespace graphics
} // namespace graphics
#endif

View File

@ -26,7 +26,7 @@ extern bool hasUnreadMessage;
namespace graphics
{
char NotificationRenderer::inEvent = INPUT_BROKER_NONE;
InputEvent NotificationRenderer::inEvent;
int8_t NotificationRenderer::curSelected = 0;
char NotificationRenderer::alertBannerMessage[256] = {0};
uint32_t NotificationRenderer::alertBannerUntil = 0; // 0 is a special case meaning forever
@ -72,11 +72,25 @@ void NotificationRenderer::resetBanner()
{
alertBannerMessage[0] = '\0';
current_notification_type = notificationTypeEnum::none;
inEvent.inputEvent = INPUT_BROKER_NONE;
inEvent.kbchar = 0;
curSelected = 0;
alertBannerOptions = 0; // last x lines are seelctable options
optionsArrayPtr = nullptr;
optionsEnumPtr = nullptr;
alertBannerCallback = NULL;
pauseBanner = false;
numDigits = 0;
currentNumber = 0;
nodeDB->pause_sort(false);
}
void NotificationRenderer::drawBannercallback(OLEDDisplay *display, OLEDDisplayUiState *state)
{
if (!isOverlayBannerShowing() && alertBannerMessage[0] != '\0')
resetBanner();
if (!isOverlayBannerShowing() || pauseBanner)
return;
switch (current_notification_type) {
@ -115,31 +129,40 @@ void NotificationRenderer::drawNumberPicker(OLEDDisplay *display, OLEDDisplayUiS
// modulo to extract
uint8_t this_digit = (currentNumber % (pow_of_10(numDigits - curSelected))) / (pow_of_10(numDigits - curSelected - 1));
// Handle input
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
if (this_digit == 9) {
currentNumber -= 9 * (pow_of_10(numDigits - curSelected - 1));
} else {
currentNumber += (pow_of_10(numDigits - curSelected - 1));
}
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
if (this_digit == 0) {
currentNumber += 9 * (pow_of_10(numDigits - curSelected - 1));
} else {
currentNumber -= (pow_of_10(numDigits - curSelected - 1));
}
} else if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_RIGHT) {
} else if (inEvent.inputEvent == INPUT_BROKER_ANYKEY) {
if (inEvent.kbchar > 47 && inEvent.kbchar < 58) { // have a digit
currentNumber -= this_digit * (pow_of_10(numDigits - curSelected - 1));
currentNumber += (inEvent.kbchar - 48) * (pow_of_10(numDigits - curSelected - 1));
curSelected++;
}
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_RIGHT) {
curSelected++;
} else if (inEvent == INPUT_BROKER_LEFT) {
} else if (inEvent.inputEvent == INPUT_BROKER_LEFT) {
curSelected--;
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
alertBannerUntil != 0) {
resetBanner();
return;
}
if (curSelected == numDigits) {
resetBanner();
alertBannerCallback(currentNumber);
resetBanner();
return;
}
inEvent = INPUT_BROKER_NONE;
inEvent.inputEvent = INPUT_BROKER_NONE;
if (alertBannerMessage[0] == '\0')
return;
@ -193,16 +216,18 @@ void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiSta
}
// Handle input
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
curSelected--;
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
curSelected++;
} else if (inEvent == INPUT_BROKER_SELECT) {
resetBanner();
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
alertBannerCallback(selectedNodenum);
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
resetBanner();
return;
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
alertBannerUntil != 0) {
resetBanner();
return;
}
if (curSelected == -1)
@ -210,7 +235,7 @@ void NotificationRenderer::drawNodePicker(OLEDDisplay *display, OLEDDisplayUiSta
if (curSelected == alertBannerOptions)
curSelected = 0;
inEvent = INPUT_BROKER_NONE;
inEvent.inputEvent = INPUT_BROKER_NONE;
if (alertBannerMessage[0] == '\0')
return;
@ -308,11 +333,11 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
// Handle input
if (alertBannerOptions > 0) {
if (inEvent == INPUT_BROKER_UP || inEvent == INPUT_BROKER_ALT_PRESS) {
if (inEvent.inputEvent == INPUT_BROKER_UP || inEvent.inputEvent == INPUT_BROKER_ALT_PRESS) {
curSelected--;
} else if (inEvent == INPUT_BROKER_DOWN || inEvent == INPUT_BROKER_USER_PRESS) {
} else if (inEvent.inputEvent == INPUT_BROKER_DOWN || inEvent.inputEvent == INPUT_BROKER_USER_PRESS) {
curSelected++;
} else if (inEvent == INPUT_BROKER_SELECT) {
} else if (inEvent.inputEvent == INPUT_BROKER_SELECT) {
if (optionsEnumPtr != nullptr) {
alertBannerCallback(optionsEnumPtr[curSelected]);
optionsEnumPtr = nullptr;
@ -320,8 +345,11 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
alertBannerCallback(curSelected);
}
resetBanner();
} else if ((inEvent == INPUT_BROKER_CANCEL || inEvent == INPUT_BROKER_ALT_LONG) && alertBannerUntil != 0) {
return;
} else if ((inEvent.inputEvent == INPUT_BROKER_CANCEL || inEvent.inputEvent == INPUT_BROKER_ALT_LONG) &&
alertBannerUntil != 0) {
resetBanner();
return;
}
if (curSelected == -1)
@ -329,12 +357,14 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp
if (curSelected == alertBannerOptions)
curSelected = 0;
} else {
if (inEvent == INPUT_BROKER_SELECT || inEvent == INPUT_BROKER_ALT_LONG || inEvent == INPUT_BROKER_CANCEL) {
if (inEvent.inputEvent == INPUT_BROKER_SELECT || inEvent.inputEvent == INPUT_BROKER_ALT_LONG ||
inEvent.inputEvent == INPUT_BROKER_CANCEL) {
resetBanner();
return;
}
}
inEvent = INPUT_BROKER_NONE;
inEvent.inputEvent = INPUT_BROKER_NONE;
if (alertBannerMessage[0] == '\0')
return;

View File

@ -11,7 +11,8 @@ namespace graphics
class NotificationRenderer
{
public:
static char inEvent;
static InputEvent inEvent;
static char inKeypress;
static int8_t curSelected;
static char alertBannerMessage[256];
static uint32_t alertBannerUntil; // 0 is a special case meaning forever

View File

@ -13,8 +13,9 @@ template <class T> constexpr const T &clamp(const T &v, const T &lo, const T &hi
#if HAS_SCREEN
#define IF_SCREEN(X) \
if (screen) \
X;
if (screen) { \
X; \
}
#else
#define IF_SCREEN(...)
#endif

View File

@ -716,7 +716,7 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
}
// Backspace
if (event->inputEvent == INPUT_BROKER_BACK) {
if (event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() > 0) {
payload = 0x08;
lastTouchMillis = millis();
runOnce();
@ -739,7 +739,8 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
}
// Cancel (dismiss freetext screen)
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG) {
if (event->inputEvent == INPUT_BROKER_CANCEL || event->inputEvent == INPUT_BROKER_ALT_LONG ||
(event->inputEvent == INPUT_BROKER_BACK && this->freetext.length() == 0)) {
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
freetext = "";
cursor = 0;
@ -989,6 +990,7 @@ int32_t CannedMessageModule::runOnce()
}
this->cursor--;
}
} else {
}
break;
case INPUT_BROKER_MSG_TAB: // Tab key: handled by input handler

View File

@ -2,6 +2,7 @@
#include "KeyVerificationModule.h"
#include "MeshService.h"
#include "RTC.h"
#include "graphics/draw/MenuHandler.h"
#include "main.h"
#include "modules/AdminModule.h"
#include <SHA256.h>
@ -48,18 +49,22 @@ AdminMessageHandleResult KeyVerificationModule::handleAdminMessageForModule(cons
bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_KeyVerification *r)
{
updateState();
if (mp.pki_encrypted == false)
if (mp.pki_encrypted == false) {
return false;
if (mp.from != currentRemoteNode) // because the inital connection request is handled in allocReply()
}
if (mp.from != currentRemoteNode) { // because the inital connection request is handled in allocReply()
return false;
}
if (currentState == KEY_VERIFICATION_IDLE) {
return false; // if we're idle, the only acceptable message is an init, which should be handled by allocReply()
}
} else if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 &&
r->hash1.size == 0) {
if (currentState == KEY_VERIFICATION_SENDER_HAS_INITIATED && r->nonce == currentNonce && r->hash2.size == 32 &&
r->hash1.size == 0) {
memcpy(hash2, r->hash2.bytes, 32);
if (screen)
screen->showSimpleBanner("Enter Security Number", 30000);
IF_SCREEN(screen->showNumberPicker("Enter Security Number", 60000, 6, [](int number_picked) -> void {
keyVerificationModule->processSecurityNumber(number_picked);
});)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
@ -79,23 +84,19 @@ bool KeyVerificationModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
memset(message, 0, sizeof(message));
sprintf(message, "Verification: \n");
generateVerificationCode(message + 15);
static const char *optionsArray[] = {"ACCEPT", "REJECT"};
static const char *optionsArray[] = {"Reject", "Accept"};
LOG_INFO("Hash1 matches!");
if (screen) {
graphics::BannerOverlayOptions options;
options.message = message;
options.durationMs = 30000;
options.optionsArrayPtr = optionsArray;
options.optionsCount = 2;
options.notificationType = graphics::notificationTypeEnum::selection_picker;
options.bannerCallback = [=](int selected) {
if (selected == 0) {
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
}
};
screen->showOverlayBanner(options);
}
IF_SCREEN(graphics::BannerOverlayOptions options; options.message = message; options.durationMs = 30000;
options.optionsArrayPtr = optionsArray; options.optionsCount = 2;
options.notificationType = graphics::notificationTypeEnum::selection_picker;
options.bannerCallback =
[=](int selected) {
if (selected == 1) {
auto remoteNodePtr = nodeDB->getMeshNode(currentRemoteNode);
remoteNodePtr->bitfield |= NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
}
};
screen->showOverlayBanner(options);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Final confirmation for incoming manual key verification %s", message);
@ -120,6 +121,7 @@ bool KeyVerificationModule::sendInitialRequest(NodeNum remoteNode)
// generate nonce
updateState();
if (currentState != KEY_VERIFICATION_IDLE) {
graphics::menuHandler::menuQueue = graphics::menuHandler::throttle_message;
return false;
}
currentNonce = random();
@ -190,11 +192,8 @@ meshtastic_MeshPacket *KeyVerificationModule::allocReply()
responsePacket = allocDataProtobuf(response);
responsePacket->pki_encrypted = true;
if (screen) {
snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000);
screen->showSimpleBanner(message, 30000);
LOG_WARN("%s", message);
}
IF_SCREEN(snprintf(message, 25, "Security Number \n%03u %03u", currentSecurityNumber / 1000, currentSecurityNumber % 1000);
screen->showSimpleBanner(message, 30000); LOG_WARN("%s", message);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Incoming Key Verification.\nSecurity Number\n%03u %03u", currentSecurityNumber / 1000,
@ -258,12 +257,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
p->priority = meshtastic_MeshPacket_Priority_HIGH;
service->sendToMesh(p, RX_SRC_LOCAL, true);
currentState = KEY_VERIFICATION_SENDER_AWAITING_USER;
memset(message, 0, sizeof(message));
sprintf(message, "Verification: \n");
generateVerificationCode(message + 15); // send the toPhone packet
if (screen) {
screen->showSimpleBanner(message, 30000);
}
IF_SCREEN(screen->requestMenu(graphics::menuHandler::key_verification_final_prompt);)
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
cn->level = meshtastic_LogRecord_Level_WARNING;
sprintf(cn->message, "Final confirmation for outgoing manual key verification %s", message);
@ -282,7 +276,7 @@ void KeyVerificationModule::processSecurityNumber(uint32_t incomingNumber)
void KeyVerificationModule::updateState()
{
if (currentState != KEY_VERIFICATION_IDLE) {
// check for the 30 second timeout
// check for the 60 second timeout
if (currentNonceTimestamp < getTime() - 60) {
resetToIdle();
} else {

View File

@ -27,6 +27,8 @@ class KeyVerificationModule : public ProtobufModule<meshtastic_KeyVerification>
}*/
virtual bool wantUIFrame() { return false; };
bool sendInitialRequest(NodeNum remoteNode);
void generateVerificationCode(char *); // fills char with the user readable verification code
uint32_t getCurrentRemoteNode() { return currentRemoteNode; }
protected:
/* Called to handle a particular incoming message
@ -56,9 +58,8 @@ class KeyVerificationModule : public ProtobufModule<meshtastic_KeyVerification>
char message[40] = {0};
void processSecurityNumber(uint32_t);
void updateState(); // check the timeouts and maybe reset the state to idle
void resetToIdle(); // Zero out module state
void generateVerificationCode(char *); // fills char with the user readable verification code
void updateState(); // check the timeouts and maybe reset the state to idle
void resetToIdle(); // Zero out module state
};
extern KeyVerificationModule *keyVerificationModule;

View File

@ -68,6 +68,7 @@
#define TB_LEFT 1
#define TB_RIGHT 2
#define TB_PRESS 0 // BUTTON_PIN
#define TB_DIRECTION FALLING
// microphone
#define ES7210_SCK 47