mirror of
https://github.com/meshtastic/firmware.git
synced 2026-09-18 19:31:56 -04:00
* fix(ui): honor mute when waking the screen for a received message TextMessageModule fired powerFSM.trigger(EVENT_RECEIVED_MSG) for every text packet, gated only by shouldWakeOnReceivedMessage(), which checks external notification, device role and battery level but never the mute flags. A muted channel therefore suppressed the banner and still lit the screen. MessageRenderer::handleNewMessage() only computed mute for MessageType::BROADCAST, so a DM from a muted node produced a banner and a wake. Add isMutedForPacket() in Channels: a DM addressed to us reads the sender's NodeInfoLite mute bit, every other packet reads the mute bit of the channel it arrived on. This is the predicate ExternalNotificationModule already applied to the buzzer, vibra and LED outputs, hoisted so all three call sites share it. Bell and alert messages still break through mute on both paths, unchanged. No protobuf or config change: ChannelSettings.module_settings.is_muted and the NodeInfoLite mute bit already exist and are already settable from the device menu and via AdminMessage.toggle_muted_node. Closes #11674 * fix(ui): let an alert break through mute on the screen wake path In COLOR display mode TextMessageModule skips handleNewMessage(), so powerFSM.trigger(EVENT_RECEIVED_MSG) is the only wake an alert gets. Gating it on mute alone dropped that wake for a bell on a muted channel. Add MeshService::isAlertPayload(): an ASCII BEL in the payload while at least one alert_bell_* output is enabled. The wake gate is now "not muted, or an alert". MessageRenderer uses the same predicate instead of its own inline bell scan, which also lifts that scan's arbitrary 100 byte cap. Rename three test cases. Their names carried exactly 35 characters after the test_ prefix, which matches the Lob API key format and tripped trufflehog in the trunk check gate.
179 lines
7.1 KiB
C++
179 lines
7.1 KiB
C++
#pragma once
|
|
|
|
#include "CryptoEngine.h"
|
|
#include "NodeDB.h"
|
|
#include "mesh-pb-constants.h"
|
|
#include <Arduino.h>
|
|
|
|
#if USERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL && !defined(USERPREFS_CHANNEL_0_PSK)
|
|
#error "USERPREFS_BLOCK_POSITION_ON_EVENT_CHANNEL requires USERPREFS_CHANNEL_0_PSK"
|
|
#endif
|
|
|
|
/** A channel number (index into the channel table)
|
|
*/
|
|
typedef uint8_t ChannelIndex;
|
|
|
|
/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex)
|
|
* Used as a hint to limit which PSKs are considered for packet decoding.
|
|
*/
|
|
typedef uint8_t ChannelHash;
|
|
|
|
/** The container/on device API for working with channels */
|
|
class Channels
|
|
{
|
|
/// The index of the primary channel
|
|
ChannelIndex primaryIndex = 0;
|
|
|
|
/** The channel index that was requested for sending/receiving. Note: if this channel is a secondary
|
|
channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled
|
|
no sending or receiving will be allowed */
|
|
ChannelIndex activeChannelIndex = 0;
|
|
|
|
/// the precomputed hashes for each of our channels, or -1 for invalid
|
|
int16_t hashes[MAX_NUM_CHANNELS] = {};
|
|
|
|
public:
|
|
Channels() {}
|
|
|
|
/// Well known channel names
|
|
static const char *adminChannel, *gpioChannel, *serialChannel, *mqttChannel;
|
|
|
|
const meshtastic_ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
|
|
|
|
/** Return the Channel for a specified index */
|
|
meshtastic_Channel &getByIndex(ChannelIndex chIndex);
|
|
|
|
/** Return the Channel for a specified name, return primary if not found. */
|
|
meshtastic_Channel &getByName(const char *chName);
|
|
|
|
/** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted
|
|
* to be primary, force all other channels to be secondary.
|
|
*/
|
|
void setChannel(const meshtastic_Channel &c);
|
|
|
|
/** Return a human friendly name for this channel (and expand any short strings as needed)
|
|
*/
|
|
const char *getName(size_t chIndex);
|
|
|
|
/**
|
|
* Return a globally unique channel ID usable with MQTT.
|
|
*/
|
|
const char *getGlobalId(size_t chIndex) { return getName(chIndex); } // FIXME, not correct
|
|
|
|
/** The index of the primary channel */
|
|
ChannelIndex getPrimaryIndex() const { return primaryIndex; }
|
|
|
|
ChannelIndex getNumChannels() { return channelFile.channels_count; }
|
|
|
|
/// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config.
|
|
void initDefaults();
|
|
|
|
/// called when the user has just changed our radio config and we might need to change channel keys
|
|
void onConfigChanged();
|
|
|
|
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
|
|
*
|
|
* This method is called before decoding inbound packets
|
|
*
|
|
* @return false if the channel hash or channel is invalid
|
|
*/
|
|
bool decryptForHash(ChannelIndex chIndex, ChannelHash channelHash);
|
|
|
|
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
|
|
*
|
|
* This method is called before encoding outbound packets
|
|
*
|
|
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
|
|
*/
|
|
int16_t setActiveByIndex(ChannelIndex channelIndex);
|
|
|
|
// Returns true if the channel has the default name and PSK
|
|
bool isDefaultChannel(ChannelIndex chIndex);
|
|
|
|
// Returns true if this channel's effective key is publicly decryptable (open or well-known/default PSK).
|
|
bool usesPublicKey(ChannelIndex chIndex);
|
|
// Returns true if the channel is "well known": its PSK is absent or a
|
|
// single-byte well-known key index, AND its name is any modem-preset
|
|
// display name (e.g. a channel named "LongFast" counts even while the
|
|
// radio runs MediumFast). Broader than isDefaultChannel, which only
|
|
// matches the current preset's name and PSK byte 1.
|
|
bool isWellKnownChannel(ChannelIndex chIndex);
|
|
|
|
// Returns true if this channel's effective key matches USERPREFS_CHANNEL_0_PSK.
|
|
bool isEventChannel(ChannelIndex chIndex);
|
|
|
|
// Returns true if we can be reached via a channel with the default settings given a region and modem preset
|
|
bool hasDefaultChannel();
|
|
|
|
// Returns true if any of our channels have enabled MQTT uplink or downlink
|
|
bool anyMqttEnabled();
|
|
|
|
bool ensureLicensedOperation();
|
|
|
|
bool setDefaultPresetCryptoForHash(ChannelHash channelHash);
|
|
|
|
/**
|
|
* Validate a channel, fixing any errors as needed
|
|
*/
|
|
meshtastic_Channel &fixupChannel(ChannelIndex chIndex);
|
|
|
|
int16_t getHash(ChannelIndex i) { return hashes[i]; }
|
|
|
|
private:
|
|
/** Given a channel index, change to use the crypto key specified by that index
|
|
*
|
|
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
|
|
*/
|
|
int16_t setCrypto(ChannelIndex chIndex);
|
|
|
|
/** Return the channel index for the specified channel hash, or -1 for not found */
|
|
int8_t getIndexByHash(ChannelHash channelHash);
|
|
|
|
/** Given a channel number, return the (0 to 255) hash for that channel
|
|
* If no suitable channel could be found, return -1
|
|
*
|
|
* called by fixupChannel when a new channel is set
|
|
*/
|
|
int16_t generateHash(ChannelIndex channelNum);
|
|
|
|
/**
|
|
* Writes the default lora config
|
|
*/
|
|
void initDefaultLoraConfig();
|
|
|
|
/**
|
|
* Write default channels defined in UserPrefs
|
|
*/
|
|
void initDefaultChannel(ChannelIndex chIndex);
|
|
|
|
/**
|
|
* Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's
|
|
* PSK)
|
|
*/
|
|
CryptoKey getKey(ChannelIndex chIndex);
|
|
};
|
|
|
|
/// Singleton channel table
|
|
extern Channels channels;
|
|
|
|
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
|
|
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
|
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
|
|
|
|
/// True if the user muted the source of this packet: the sender for a DM addressed to us,
|
|
/// otherwise the channel it arrived on.
|
|
bool isMutedForPacket(const meshtastic_MeshPacket &mp);
|
|
|
|
/// True if a getKey()-resolved key offers no privacy: length 0 (off) or the public defaultpsk family. Pure; for tests.
|
|
bool cryptoKeyIsPublic(const CryptoKey &key);
|
|
|
|
/// True if channel `chIndex` in a raw ChannelFile is publicly decryptable (open / single-byte well-known
|
|
/// index / defaultpsk family). Pure equivalent of Channels::usesPublicKey that operates on the on-disk
|
|
/// struct directly, so it is callable before the `channels` singleton is initialized (e.g. during the
|
|
/// NodeDB boot migration). Resolves a PSK-less SECONDARY against the PRIMARY channel's key. For tests.
|
|
bool channelFileUsesPublicKey(const meshtastic_ChannelFile &cf, ChannelIndex chIndex);
|
|
|
|
static const uint8_t eventpsk[] = {0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36,
|
|
0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74,
|
|
0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1};
|