Browse Source

Guard channel content filter behind WITH_CHANNEL_FILTER

Feature is now fully compiled out unless built with -D WITH_CHANNEL_FILTER.

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

4
docs/cli_commands.md

@ -118,6 +118,8 @@ This document provides an overview of CLI commands that can be sent to MeshCore
## Channel Content Filter (Repeater Only)
> **Compile-time feature.** These commands only exist when the firmware is built with `-D WITH_CHANNEL_FILTER`. Without that build flag the feature is fully compiled out (no code, no storage, no CLI commands) and the repeater behaves exactly as stock.
Lets a repeater decrypt channels it holds the key for, inspect the plaintext, and refuse to retransmit messages that match a blocked keyword or sender name. With nothing configured, behaviour is identical to a stock repeater.
**How it works:** the repeater only decrypts channels you explicitly load a key for (see `filter channel`). For those channels it reads the sender name and message text; any message matching a blocked keyword (text, case-insensitive substring) or blocked sender (case-insensitive substring of the sender name) is dropped instead of forwarded. All other channels — and direct messages — are never decrypted and forward exactly as before.
@ -131,7 +133,7 @@ Lets a repeater decrypt channels it holds the key for, inspect the plaintext, an
**Config storage:** persisted to `/channel_filter` on the node's filesystem.
**Build flags:** `MAX_FILTER_CHANNELS` (default `4`), `MAX_FILTER_TERMS` (default `8`, applies to keywords and senders independently).
**Build flags:** `WITH_CHANNEL_FILTER` (required, enables the feature), `MAX_FILTER_CHANNELS` (default `4`), `MAX_FILTER_TERMS` (default `8`, applies to keywords and senders independently).
---

13
examples/simple_repeater/MyMesh.cpp

@ -1,8 +1,10 @@
#include "MyMesh.h"
#include "UnicodeFold.h"
#include <algorithm>
#include <ctype.h>
#ifdef WITH_CHANNEL_FILTER
#include "UnicodeFold.h"
/* --------------------- public-channel content filter ------------------ */
// The well-known MeshCore public channel PSK ("izOH6cXN6mrJ5e26oRXNcg==")
@ -35,6 +37,7 @@ static int decodeBase64(const char* in, uint8_t* out, int max_out) {
}
return n;
}
#endif // WITH_CHANNEL_FILTER
/* ------------------------------ Config -------------------------------- */
@ -663,6 +666,7 @@ void MyMesh::getPeerSharedSecret(uint8_t *dest_secret, int peer_idx) {
}
}
#ifdef WITH_CHANNEL_FILTER
bool MyMesh::addFilterChannel(const char *psk_b64) {
if (num_filter_channels >= MAX_FILTER_CHANNELS) return false;
@ -865,6 +869,7 @@ void MyMesh::handleFilterCommand(char *command, char *reply) {
}
strcpy(reply, "Err - usage: filter [list|stats [reset]|channel <b64|public|clear>|block <kw>|sender <name>|clear|reset]");
}
#endif // WITH_CHANNEL_FILTER
static bool isShare(const mesh::Packet *packet) {
if (packet->hasTransportCodes()) {
@ -1101,10 +1106,12 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
{
last_millis = 0;
uptime_millis = 0;
#ifdef WITH_CHANNEL_FILTER
num_filter_channels = 0;
num_block_keywords = 0;
num_block_senders = 0;
n_filtered = 0;
#endif
next_local_advert = next_flood_advert = 0;
dirty_contacts_expiry = 0;
set_radio_at = revert_radio_at = 0;
@ -1173,7 +1180,9 @@ void MyMesh::begin(FILESYSTEM *fs) {
// load persisted prefs
_cli.loadPrefs(_fs);
acl.load(_fs, self_id);
#ifdef WITH_CHANNEL_FILTER
loadChannelFilter();
#endif
// TODO: key_store.begin();
region_map.load(_fs);
@ -1501,8 +1510,10 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
sendNodeDiscoverReq();
strcpy(reply, "OK - Discover sent");
}
#ifdef WITH_CHANNEL_FILTER
} else if (memcmp(command, "filter", 6) == 0 && (command[6] == 0 || command[6] == ' ')) {
handleFilterCommand(command, reply);
#endif
} else{
_cli.handleCommand(sender_timestamp, command, reply); // common CLI commands
}

9
examples/simple_repeater/MyMesh.h

@ -79,6 +79,8 @@ struct NeighbourInfo {
#define FIRMWARE_ROLE "repeater"
#define PACKET_LOG_FILE "/packet_log"
#ifdef WITH_CHANNEL_FILTER
#define CHANNEL_FILTER_FILE "/channel_filter"
#ifndef MAX_FILTER_CHANNELS
@ -89,6 +91,7 @@ struct NeighbourInfo {
#endif
#define FILTER_TERM_LEN 24
#define FILTER_PSK_B64_LEN 48
#endif
class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
FILESYSTEM* _fs;
@ -124,6 +127,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
uint8_t pending_cr;
int matching_peer_indexes[MAX_CLIENTS];
#ifdef WITH_CHANNEL_FILTER
mesh::GroupChannel filter_channels[MAX_FILTER_CHANNELS];
char filter_channel_psk[MAX_FILTER_CHANNELS][FILTER_PSK_B64_LEN];
uint8_t num_filter_channels;
@ -132,6 +136,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
char block_senders[MAX_FILTER_TERMS][FILTER_TERM_LEN];
uint8_t num_block_senders;
uint32_t n_filtered;
#endif
#if defined(WITH_RS232_BRIDGE)
RS232Bridge bridge;
#elif defined(WITH_ESPNOW_BRIDGE)
@ -149,10 +154,12 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
File openAppend(const char* fname);
bool isLooped(const mesh::Packet* packet, const uint8_t max_counters[]);
#ifdef WITH_CHANNEL_FILTER
bool addFilterChannel(const char* psk_b64);
void loadChannelFilter();
void saveChannelFilter();
void handleFilterCommand(char* command, char* reply);
#endif
protected:
float getAirtimeBudgetFactor() const override {
@ -191,8 +198,10 @@ protected:
void onAnonDataRecv(mesh::Packet* packet, const uint8_t* secret, const mesh::Identity& sender, uint8_t* data, size_t len) override;
int searchPeersByHash(const uint8_t* hash) override;
#ifdef WITH_CHANNEL_FILTER
int searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel channels[], int max_matches) override;
void onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mesh::GroupChannel& channel, uint8_t* data, size_t len) override;
#endif
void getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) override;
void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, uint32_t timestamp, const uint8_t* app_data, size_t app_data_len);
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;

Loading…
Cancel
Save