Browse Source

filter channel: accept a raw hex key in addition to base64

A 16/32-byte key is 32/64 hex chars while base64 PSKs are 24/44 chars, so
all-hex-and-32/64-long disambiguates cleanly. Widen the stored-PSK buffer to
fit a 64-char hex key.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
pull/2733/head
Kemal Hadimli 2 days ago
parent
commit
6cbbe1500a
  1. 2
      docs/cli_commands.md
  2. 26
      examples/simple_repeater/MyMesh.cpp
  3. 6
      examples/simple_repeater/MyMesh.h

2
docs/cli_commands.md

@ -1144,7 +1144,7 @@ Repeater only. Lets a repeater decrypt channels it holds the key for, inspect th
- `filter channel clear` - `filter channel clear`
**Parameters:** **Parameters:**
- `psk`: Channel pre-shared key in Base64 (16 or 32 bytes when decoded), e.g. the value shared by a MeshCore client. The literal `public` is a shortcut for the well-known public channel key. - `psk`: Channel pre-shared key, as either Base64 (the form MeshCore clients share, e.g. `izOH6cXN6mrJ5e26oRXNcg==`) or raw hex (`62be0e1267c401381f4ea6f44217d7a9`). Either way it must decode to 16 or 32 bytes. The literal `public` is a shortcut for the well-known public channel key.
**Note:** Adding a channel only enables decryption/inspection of that channel; messages still forward normally unless they match a blocked keyword or sender. `filter channel clear` removes all channel keys (the repeater stops decrypting and forwards everything blind again). **Note:** Adding a channel only enables decryption/inspection of that channel; messages still forward normally unless they match a blocked keyword or sender. `filter channel clear` removes all channel keys (the repeater stops decrypting and forwards everything blind again).

26
examples/simple_repeater/MyMesh.cpp

@ -36,6 +36,17 @@ static int decodeBase64(const char* in, uint8_t* out, int max_out) {
} }
return n; return n;
} }
// A 16/32-byte key in hex is 32/64 chars; base64 PSKs are 24/44 chars, so the
// length is unambiguous as long as every char is a hex digit.
static bool isHexKey(const char* s) {
int n = 0;
for (const char* p = s; *p; p++, n++) {
char c = *p;
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) return false;
}
return n == 32 || n == 64;
}
#endif // WITH_CHANNEL_FILTER #endif // WITH_CHANNEL_FILTER
@ -666,23 +677,26 @@ void MyMesh::getPeerSharedSecret(uint8_t *dest_secret, int peer_idx) {
} }
#ifdef WITH_CHANNEL_FILTER #ifdef WITH_CHANNEL_FILTER
bool MyMesh::addFilterChannel(const char *psk_b64) { bool MyMesh::addFilterChannel(const char *psk) {
if (num_filter_channels >= MAX_FILTER_CHANNELS) return false; if (num_filter_channels >= MAX_FILTER_CHANNELS) return false;
auto ch = &filter_channels[num_filter_channels]; auto ch = &filter_channels[num_filter_channels];
memset(ch->secret, 0, sizeof(ch->secret)); memset(ch->secret, 0, sizeof(ch->secret));
int len; int len;
if (strcmp(psk_b64, "public") == 0) { if (strcmp(psk, "public") == 0) {
memcpy(ch->secret, PUBLIC_CHANNEL_SECRET, sizeof(PUBLIC_CHANNEL_SECRET)); memcpy(ch->secret, PUBLIC_CHANNEL_SECRET, sizeof(PUBLIC_CHANNEL_SECRET));
len = sizeof(PUBLIC_CHANNEL_SECRET); len = sizeof(PUBLIC_CHANNEL_SECRET);
} else if (isHexKey(psk)) {
len = strlen(psk) / 2;
if (!mesh::Utils::fromHex(ch->secret, len, psk)) return false;
} else { } else {
len = decodeBase64(psk_b64, ch->secret, sizeof(ch->secret)); len = decodeBase64(psk, ch->secret, sizeof(ch->secret));
} }
if (len != 16 && len != 32) return false; if (len != 16 && len != 32) return false;
mesh::Utils::sha256(ch->hash, sizeof(ch->hash), ch->secret, len); mesh::Utils::sha256(ch->hash, sizeof(ch->hash), ch->secret, len);
StrHelper::strncpy(filter_channel_psk[num_filter_channels], psk_b64, FILTER_PSK_B64_LEN); StrHelper::strncpy(filter_channel_psk[num_filter_channels], psk, FILTER_PSK_LEN);
num_filter_channels++; num_filter_channels++;
return true; return true;
} }
@ -767,7 +781,7 @@ void MyMesh::loadChannelFilter() {
#endif #endif
if (!f) return; if (!f) return;
char line[FILTER_PSK_B64_LEN + 8]; char line[FILTER_PSK_LEN + 8];
while (f.available()) { while (f.available()) {
int n = f.readBytesUntil('\n', (uint8_t *)line, sizeof(line) - 1); int n = f.readBytesUntil('\n', (uint8_t *)line, sizeof(line) - 1);
line[n] = 0; line[n] = 0;
@ -868,7 +882,7 @@ void MyMesh::handleFilterCommand(char *command, char *reply) {
strcpy(reply, "OK - filter reset"); strcpy(reply, "OK - filter reset");
return; return;
} }
strcpy(reply, "Err - usage: filter [list|stats [reset]|channel <b64|public|clear>|block <kw>|sender <name>|clear|reset]"); strcpy(reply, "Err - usage: filter [list|stats [reset]|channel <b64|hex|public|clear>|block <kw>|sender <name>|clear|reset]");
} }
#endif // WITH_CHANNEL_FILTER #endif // WITH_CHANNEL_FILTER

6
examples/simple_repeater/MyMesh.h

@ -90,7 +90,7 @@ struct NeighbourInfo {
#define MAX_FILTER_TERMS 8 #define MAX_FILTER_TERMS 8
#endif #endif
#define FILTER_TERM_LEN 24 #define FILTER_TERM_LEN 24
#define FILTER_PSK_B64_LEN 48 #define FILTER_PSK_LEN 68 // fits a 64-char hex key, a 44-char base64 PSK, or "public"
#endif #endif
class MyMesh : public mesh::Mesh, public CommonCLICallbacks { class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
@ -129,7 +129,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
#ifdef WITH_CHANNEL_FILTER #ifdef WITH_CHANNEL_FILTER
mesh::GroupChannel filter_channels[MAX_FILTER_CHANNELS]; mesh::GroupChannel filter_channels[MAX_FILTER_CHANNELS];
char filter_channel_psk[MAX_FILTER_CHANNELS][FILTER_PSK_B64_LEN]; char filter_channel_psk[MAX_FILTER_CHANNELS][FILTER_PSK_LEN];
uint8_t num_filter_channels; uint8_t num_filter_channels;
char block_keywords[MAX_FILTER_TERMS][FILTER_TERM_LEN]; char block_keywords[MAX_FILTER_TERMS][FILTER_TERM_LEN];
uint8_t num_block_keywords; uint8_t num_block_keywords;
@ -155,7 +155,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
bool isLooped(const mesh::Packet* packet, const uint8_t max_counters[]); bool isLooped(const mesh::Packet* packet, const uint8_t max_counters[]);
#ifdef WITH_CHANNEL_FILTER #ifdef WITH_CHANNEL_FILTER
bool addFilterChannel(const char* psk_b64); bool addFilterChannel(const char* psk);
void loadChannelFilter(); void loadChannelFilter();
void saveChannelFilter(); void saveChannelFilter();
void handleFilterCommand(char* command, char* reply); void handleFilterCommand(char* command, char* reply);

Loading…
Cancel
Save