Browse Source

filter channel: remove a single channel by key

Add `filter channel remove <#name|psk|public>` to drop one channel instead
of clearing all. Matched by the resolved key, so any equivalent spec works.
Decode logic shared between add and remove via decodeChannelKey().

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

3
docs/cli_commands.md

@ -1142,13 +1142,14 @@ Repeater only. Lets a repeater decrypt channels it holds the key for, inspect th
- `filter channel <#name>`
- `filter channel <psk>`
- `filter channel public`
- `filter channel remove <#name|psk|public>`
- `filter channel clear`
**Parameters:**
- `#name`: A hashtag channel, given by its name (e.g. `#selftest`). The key is derived the same way MeshCore clients derive it — the first 16 bytes of `SHA256("#name")` — so you don't need to paste a key. Only works for hashtag channels (named channels like `public` use a random key, not a name-derived one).
- `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 remove <key>` drops a single channel — give it the same `#name`/PSK/`public` you added it with (it's matched by the resulting key, so any equivalent form works). `filter channel clear` removes all channel keys (the repeater stops decrypting and forwards everything blind again).
---

36
examples/simple_repeater/MyMesh.cpp

@ -677,10 +677,8 @@ void MyMesh::getPeerSharedSecret(uint8_t *dest_secret, int peer_idx) {
}
#ifdef WITH_CHANNEL_FILTER
bool MyMesh::addFilterChannel(const char *psk) {
if (num_filter_channels >= MAX_FILTER_CHANNELS) return false;
auto ch = &filter_channels[num_filter_channels];
// Resolve a channel spec (#name | hex | base64 | "public") into a GroupChannel.
static bool decodeChannelKey(const char *psk, mesh::GroupChannel *ch) {
memset(ch->secret, 0, sizeof(ch->secret));
int len;
@ -701,10 +699,29 @@ bool MyMesh::addFilterChannel(const char *psk) {
if (len != 16 && len != 32) return false;
mesh::Utils::sha256(ch->hash, sizeof(ch->hash), ch->secret, len);
return true;
}
bool MyMesh::addFilterChannel(const char *psk) {
if (num_filter_channels >= MAX_FILTER_CHANNELS) return false;
if (!decodeChannelKey(psk, &filter_channels[num_filter_channels])) return false;
num_filter_channels++;
return true;
}
bool MyMesh::removeFilterChannel(const char *psk) {
mesh::GroupChannel ch;
if (!decodeChannelKey(psk, &ch)) return false;
for (int i = 0; i < num_filter_channels; i++) {
if (memcmp(filter_channels[i].secret, ch.secret, sizeof(ch.secret)) == 0) {
for (int j = i; j < num_filter_channels - 1; j++) filter_channels[j] = filter_channels[j + 1];
num_filter_channels--;
return true;
}
}
return false; // no channel with that key
}
int MyMesh::searchChannelsByHash(const uint8_t *hash, mesh::GroupChannel channels[], int max_matches) {
int n = 0;
for (int i = 0; i < num_filter_channels && n < max_matches; i++) {
@ -877,6 +894,15 @@ void MyMesh::handleFilterCommand(char *command, char *reply) {
num_filter_channels = 0;
saveChannelFilter();
strcpy(reply, "OK - channels cleared");
} else if (memcmp(val, "remove ", 7) == 0) {
char *spec = val + 7;
while (*spec == ' ') spec++;
if (removeFilterChannel(spec)) {
saveChannelFilter();
sprintf(reply, "OK - %d channel(s)", num_filter_channels);
} else {
strcpy(reply, "Err - channel not found");
}
} else if (addFilterChannel(val)) {
saveChannelFilter();
sprintf(reply, "OK - %d channel(s)", num_filter_channels);
@ -918,7 +944,7 @@ void MyMesh::handleFilterCommand(char *command, char *reply) {
strcpy(reply, "OK - filter reset");
return;
}
strcpy(reply, "Err - usage: filter [list|stats [reset]|channel <#name|b64|hex|public|clear>|block <kw>|sender <name>|clear|reset]");
strcpy(reply, "Err - usage: filter [list|stats [reset]|channel <#name|b64|hex|public|remove <key>|clear>|block <kw>|sender <name>|clear|reset]");
}
#endif // WITH_CHANNEL_FILTER

1
examples/simple_repeater/MyMesh.h

@ -155,6 +155,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
#ifdef WITH_CHANNEL_FILTER
bool addFilterChannel(const char* psk);
bool removeFilterChannel(const char* psk);
void loadChannelFilter();
void saveChannelFilter();
void handleFilterCommand(char* command, char* reply);

Loading…
Cancel
Save