Files
HaloKeymind/test/test_webconfig_keys/test_webconfig_keys.cpp
T

167 lines
6.4 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("mqtt.neighbors"));
EXPECT_TRUE(wcIsAllowedSetKey("mqtt.neighbors.interval"));
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, AdminPasswordIsNotAnAllowlistedSetKey) {
EXPECT_TRUE(wcIsAdminPasswordKey("password"));
EXPECT_FALSE(wcIsAdminPasswordKey("admin.password"));
EXPECT_FALSE(wcIsAdminPasswordKey(""));
EXPECT_FALSE(wcIsAllowedSetKey("password")); // never reachable as `set password`
}
TEST(WebConfigKeys, AdminPasswordFitsNodePrefsAndRejectsLineBreaks) {
EXPECT_FALSE(wcIsValidAdminPassword(NULL));
EXPECT_FALSE(wcIsValidAdminPassword(""));
EXPECT_TRUE(wcIsValidAdminPassword("new-password"));
EXPECT_TRUE(wcIsValidAdminPassword("123456789012345"));
EXPECT_FALSE(wcIsValidAdminPassword("1234567890123456"));
EXPECT_FALSE(wcIsValidAdminPassword("line\nbreak"));
EXPECT_FALSE(wcIsValidAdminPassword("line\rbreak"));
}
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;
}
}
// ---- request correlation -------------------------------------------------
TEST(WebConfigKeys, AcceptsExactHexRequestIds) {
EXPECT_TRUE(wcIsValidReqId("0123456789abcdef"));
EXPECT_TRUE(wcIsValidReqId("ABCDEF0123456789"));
}
TEST(WebConfigKeys, RejectsMissingMalformedOrWrongLengthRequestIds) {
EXPECT_FALSE(wcIsValidReqId(NULL));
EXPECT_FALSE(wcIsValidReqId(""));
EXPECT_FALSE(wcIsValidReqId("0123456789abcde"));
EXPECT_FALSE(wcIsValidReqId("0123456789abcdef0"));
EXPECT_FALSE(wcIsValidReqId("0123456789abcdeg"));
EXPECT_FALSE(wcIsValidReqId("01234567-9abcdef"));
EXPECT_FALSE(wcIsValidReqId("01234567 9abcdef"));
}
// ---- browser terminal commands -------------------------------------------
TEST(WebConfigKeys, AcceptsSingleLineCliCommands) {
EXPECT_TRUE(wcIsValidCliCommand("get wifi.status"));
EXPECT_TRUE(wcIsValidCliCommand("set flood.max 12"));
EXPECT_TRUE(wcIsValidCliCommand(" neighbors "));
}
TEST(WebConfigKeys, RejectsBlankMultilineOrOversizedCliCommands) {
EXPECT_FALSE(wcIsValidCliCommand(NULL));
EXPECT_FALSE(wcIsValidCliCommand(""));
EXPECT_FALSE(wcIsValidCliCommand(" \t"));
EXPECT_FALSE(wcIsValidCliCommand("get role\nreboot"));
EXPECT_FALSE(wcIsValidCliCommand("get role\rreboot"));
char max_command[160];
memset(max_command, 'x', sizeof(max_command) - 1);
max_command[sizeof(max_command) - 1] = 0;
EXPECT_TRUE(wcIsValidCliCommand(max_command));
char oversized[161];
memset(oversized, 'x', sizeof(oversized) - 1);
oversized[sizeof(oversized) - 1] = 0;
EXPECT_FALSE(wcIsValidCliCommand(oversized));
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}