From 72e99d14c5dce8cac65668de4d3a2e625f538983 Mon Sep 17 00:00:00 2001 From: cjkas Date: Sun, 25 Oct 2026 11:11:19 +0100 Subject: [PATCH] fix: drop Secure Config Only permissions from protocol 2 The socket has two modes, None and Secured (ADR 0006), and ignores the ConfigOnly bit, so the security section no longer reads or saves it. The HTTP routes keep it until step 4 removes the mode. Co-Authored-By: Claude Opus 5.5 --- docs/PROTOCOL.md | 2 +- src/DeviceOps.cpp | 3 ++- src/ProtoSchema.h | 1 - src/ProtoSettings.cpp | 1 - test/test_protosettings/test_protosettings.cpp | 5 +++++ 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md index 7c71330..214c229 100644 --- a/docs/PROTOCOL.md +++ b/docs/PROTOCOL.md @@ -135,7 +135,7 @@ The settings are in five sections. `getSettings` and `saveSettings` name one in | `general` | `hostname`, `ssdpBroadcast`, `ntpServer`, `posixZone` | `/modulesettings`, `/setgeneral` | | `network` | `connMode`; WiFi: `ssid`, `passphrase`, `roaming`, `hidden`; Ethernet: `boardType`, `phyType`, `CLKMode`, `phyAddress`, `PWRPin`, `MDCPin`, `MDIOPin`; the address: `dhcp`, `ip`, `gateway`, `subnet`, `dns1`, `dns2` | `/networksettings`, `/setNetwork`, `/setIP`, `/connectwifi` | | `mqtt` | `enabled`, `pubDisco`, `protocol`, `hostname` (the broker's), `port`, `username`, `password`, `rootTopic`, `discoTopic` | `/mqttsettings`, `/connectmqtt` | -| `security` | `securityType`, `username`, `password`, `pin`, `permissions` | `/getSecurity`, `/saveSecurity` | +| `security` | `securityType`, `username`, `password`, `pin` | `/getSecurity`, `/saveSecurity` | | `radio` | `bitLength`, `proto`, `enabled`, `TXPin`, `RXPin`, `SCKPin`, `MOSIPin`, `MISOPin`, `CSNPin`, `frequency`, `rxBandwidth`, `deviation`, `txPower`, `noiseDetection` | `/getRadio`, `/saveRadio` | - **Reading.** `getSettings` replies with the section's fields. A secret is never sent: `hasPassphrase`, `hasPassword` and `hasPin` say whether one is set. `network` also has `hasEthernet`, and has the Ethernet fields only on a device with Ethernet. `radio` also has `radioInit`. diff --git a/src/DeviceOps.cpp b/src/DeviceOps.cpp index 543347f..0361008 100644 --- a/src/DeviceOps.cpp +++ b/src/DeviceOps.cpp @@ -91,7 +91,8 @@ static void writeSettings(ProtoWriter &w, settings_section_t section) { w.add(proto_field_t::username, settings.Security.username); w.add(proto_field_t::hasPassword, hasSecret(settings.Security.password)); w.add(proto_field_t::hasPin, hasSecret(settings.Security.pin)); - w.add(proto_field_t::permissions, settings.Security.permissions); + // Not "Secure Config Only"'s permissions: the socket has two modes, None + // and Secured (docs/adr/0006-two-security-modes-eleven-http-routes.md). break; case settings_section_t::radio: { const transceiver_config_t &cfg = somfy.transceiver.config; diff --git a/src/ProtoSchema.h b/src/ProtoSchema.h index 11b4d23..dc5a853 100644 --- a/src/ProtoSchema.h +++ b/src/ProtoSchema.h @@ -238,7 +238,6 @@ FIELD(securityType, "sy", 'i', 0) \ FIELD(pin, "pn", 's', 0) \ FIELD(hasPin, "hi", 'b', 0) \ - FIELD(permissions, "pm", 'i', 0) \ /* the radio: bitLength, proto, frequency and enabled as above */ \ FIELD(TXPin, "tx", 'i', 0) \ FIELD(RXPin, "rx", 'i', 0) \ diff --git a/src/ProtoSettings.cpp b/src/ProtoSettings.cpp index ee62ec5..e1b6c18 100644 --- a/src/ProtoSettings.cpp +++ b/src/ProtoSettings.cpp @@ -70,7 +70,6 @@ static const settings_field_t FIELDS[] = { {settings_part_t::security, proto_field_t::username, nullptr, 0, 32}, {settings_part_t::security, proto_field_t::password, nullptr, 0, 32}, {settings_part_t::security, proto_field_t::pin, nullptr, 0, 4}, - {settings_part_t::security, proto_field_t::permissions, nullptr, 0, 1}, // 56 or 80, checked on its own. {settings_part_t::radio, proto_field_t::bitLength, "type", 56, 80}, // RTS, RTW, RTV, GP Relay or GP Remote (radio_proto), checked on its own. diff --git a/test/test_protosettings/test_protosettings.cpp b/test/test_protosettings/test_protosettings.cpp index b8749c2..f1e2ec7 100644 --- a/test/test_protosettings/test_protosettings.cpp +++ b/test/test_protosettings/test_protosettings.cpp @@ -161,6 +161,10 @@ static void test_a_field_of_another_section_is_refused() { TEST_ASSERT_EQUAL_STRING("TXPin can't be saved in mqtt", expand(R"({"se":"mqtt","tx":12})")); TEST_ASSERT_EQUAL_STRING("shadeId can't be saved in radio", expand(R"({"se":"radio","s":1})")); } +static void test_secure_config_only_is_not_a_field() { + // Two modes, None and Secured (ADR 0006): "Secure Config Only" has no key. + TEST_ASSERT_EQUAL_STRING("Unknown field pm", expand(R"({"se":"security","pm":1})")); +} static void test_ethernet_needs_a_chip_with_it() { TEST_ASSERT_GOOD(expand(R"({"se":"network","bo":1})")); TEST_ASSERT_EQUAL_STRING("This device has no Ethernet", expand(R"({"se":"network","bo":1})", false)); @@ -211,6 +215,7 @@ int main(int argc, char **argv) { RUN_TEST(test_an_unknown_key_is_refused); RUN_TEST(test_what_is_only_sent_is_refused); RUN_TEST(test_a_field_of_another_section_is_refused); + RUN_TEST(test_secure_config_only_is_not_a_field); RUN_TEST(test_ethernet_needs_a_chip_with_it); RUN_TEST(test_a_save_sets_the_parts_it_has_fields_of); RUN_TEST(test_a_route_name_belongs_to_its_section);