diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 4b5c4a484..ab2396b34 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -1146,7 +1146,7 @@ Repeater only. Lets a repeater decrypt channels it holds the key for, inspect th - `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). +- `#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. Case-insensitive: the name is lowercased before hashing (hashtag names are `[a-z0-9-]`). 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 remove ` 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). diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 2f12491dd..02a24e6f9 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -686,8 +686,16 @@ static bool decodeChannelKey(const char *psk, mesh::GroupChannel *ch) { memcpy(ch->secret, PUBLIC_CHANNEL_SECRET, sizeof(PUBLIC_CHANNEL_SECRET)); len = sizeof(PUBLIC_CHANNEL_SECRET); } else if (psk[0] == '#') { // hashtag channel: key = first 16 bytes of SHA256(name) + // hashtag names are [a-z0-9-], so lowercase the input to forgive operator case + char name[40]; + int n = 0; + for (; psk[n] && n < (int)sizeof(name) - 1; n++) { + char c = psk[n]; + name[n] = (c >= 'A' && c <= 'Z') ? c + 32 : c; + } + name[n] = 0; uint8_t full[32]; - mesh::Utils::sha256(full, sizeof(full), (const uint8_t *)psk, strlen(psk)); + mesh::Utils::sha256(full, sizeof(full), (const uint8_t *)name, n); memcpy(ch->secret, full, 16); len = 16; } else if (isHexKey(psk)) {