mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-01 23:58:20 +00:00
Include detailed instructions for local testing of observer and WiFi functionality without hardware. Document the use of a mock backend and Wokwi ESP32-S3 simulation for easier development and testing. Enhance the MQTT implementation documentation to improve developer experience and facilitate testing workflows.
105 lines
4.0 KiB
C++
105 lines
4.0 KiB
C++
// Host tests for the WebConfig key allowlist / secret / slot-prefix helpers
|
|
// (src/helpers/WebConfigKeys.h). These parse attacker-supplied POST keys, so
|
|
// coverage of the length-guard and boundary cases matters for safety.
|
|
#include <gtest/gtest.h>
|
|
#include "helpers/WebConfigKeys.h"
|
|
|
|
// ---- allowlist ------------------------------------------------------------
|
|
|
|
TEST(WebConfigKeys, AllowsKnownScalarKeys) {
|
|
EXPECT_TRUE(wcIsAllowedSetKey("name"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("radio"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("repeat"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("wifi.ssid"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt.iata"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("snmp.community"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("timezone.offset"));
|
|
}
|
|
|
|
TEST(WebConfigKeys, AllowsPerSlotKeys) {
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt1.preset"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt1.server"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt1.token"));
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt6.audience")); // MAX_MQTT_SLOTS == 6
|
|
}
|
|
|
|
TEST(WebConfigKeys, RejectsDangerousOrUnknownKeys) {
|
|
EXPECT_FALSE(wcIsAllowedSetKey("erase"));
|
|
EXPECT_FALSE(wcIsAllowedSetKey("password"));
|
|
EXPECT_FALSE(wcIsAllowedSetKey("reboot"));
|
|
EXPECT_FALSE(wcIsAllowedSetKey("bogus"));
|
|
EXPECT_FALSE(wcIsAllowedSetKey("mqtt1.bogus")); // unknown slot field
|
|
EXPECT_FALSE(wcIsAllowedSetKey(""));
|
|
}
|
|
|
|
TEST(WebConfigKeys, SlotIndexBoundsMatchMaxSlots) {
|
|
EXPECT_FALSE(wcIsAllowedSetKey("mqtt0.preset")); // slot 0 invalid
|
|
EXPECT_TRUE(wcIsAllowedSetKey("mqtt6.preset")); // last valid slot
|
|
EXPECT_FALSE(wcIsAllowedSetKey("mqtt7.preset")); // beyond MAX_MQTT_SLOTS
|
|
EXPECT_FALSE(wcIsAllowedSetKey("mqtt9.preset"));
|
|
}
|
|
|
|
TEST(WebConfigKeys, IsCaseSensitive) {
|
|
EXPECT_FALSE(wcIsAllowedSetKey("Name"));
|
|
EXPECT_FALSE(wcIsAllowedSetKey("MQTT1.preset"));
|
|
}
|
|
|
|
// ---- short-key OOB guard --------------------------------------------------
|
|
// The slot-prefix probe indexes key[4..6]; these short strings must be rejected
|
|
// without ever reading past the terminator.
|
|
|
|
TEST(WebConfigKeys, ShortKeysRejectedSafely) {
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix(""));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("m"));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mq"));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqt"));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqtt")); // 4 chars — no digit/dot
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqtt1")); // 5 chars — no dot
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqtt1.")); // 6 chars — no field char
|
|
EXPECT_TRUE(wcIsSlotKeyPrefix("mqtt1.x")); // 7 chars — minimum valid
|
|
// Same guard via the public allowlist/secret entry points:
|
|
EXPECT_FALSE(wcIsAllowedSetKey("mqtt"));
|
|
EXPECT_FALSE(wcIsSecretKey("m"));
|
|
EXPECT_FALSE(wcIsSecretKey("mqtt"));
|
|
}
|
|
|
|
TEST(WebConfigKeys, SlotPrefixDigitRange) {
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqtt0.x"));
|
|
EXPECT_TRUE(wcIsSlotKeyPrefix("mqtt6.x"));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqtt7.x"));
|
|
EXPECT_FALSE(wcIsSlotKeyPrefix("mqttA.x")); // non-digit
|
|
}
|
|
|
|
// ---- secret classification ------------------------------------------------
|
|
|
|
TEST(WebConfigKeys, SecretKeysDetected) {
|
|
EXPECT_TRUE(wcIsSecretKey("wifi.pwd"));
|
|
EXPECT_TRUE(wcIsSecretKey("mqtt1.password"));
|
|
EXPECT_TRUE(wcIsSecretKey("mqtt3.token"));
|
|
EXPECT_TRUE(wcIsSecretKey("mqtt6.password"));
|
|
}
|
|
|
|
TEST(WebConfigKeys, NonSecretKeysNotFlagged) {
|
|
EXPECT_FALSE(wcIsSecretKey("wifi.ssid"));
|
|
EXPECT_FALSE(wcIsSecretKey("mqtt1.username")); // username is not masked
|
|
EXPECT_FALSE(wcIsSecretKey("mqtt1.server"));
|
|
EXPECT_FALSE(wcIsSecretKey("mqtt.origin"));
|
|
EXPECT_FALSE(wcIsSecretKey("name"));
|
|
EXPECT_FALSE(wcIsSecretKey(""));
|
|
}
|
|
|
|
TEST(WebConfigKeys, EverySecretKeyIsAlsoAllowed) {
|
|
// A secret key must be one the portal can actually set, or the masking is moot.
|
|
const char* secrets[] = {"wifi.pwd", "mqtt1.password", "mqtt1.token",
|
|
"mqtt6.password", "mqtt6.token"};
|
|
for (const char* k : secrets) {
|
|
EXPECT_TRUE(wcIsSecretKey(k)) << k;
|
|
EXPECT_TRUE(wcIsAllowedSetKey(k)) << k;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|