#include #include "apikey.hpp" using namespace svapi; TEST(KeyOp, StringRoundTrip) { EXPECT_EQ(keyOpToString(KeyOp::Search), "search"); EXPECT_EQ(*keyOpFromString("insert"), KeyOp::Insert); EXPECT_FALSE(keyOpFromString("bogus").has_value()); } TEST(KeyScope, ExactAndGlobRuleMatch) { KeyScope s; s.rules.push_back({"catalog_*", {KeyOp::Read, KeyOp::List}, false}); s.rules.push_back({"quotes", {KeyOp::Insert}, false}); EXPECT_NE(s.findRule("catalog_doors", KeyOp::Read), nullptr); EXPECT_EQ(s.findRule("catalog_doors", KeyOp::Insert), nullptr); EXPECT_NE(s.findRule("quotes", KeyOp::Insert), nullptr); EXPECT_EQ(s.findRule("designs", KeyOp::Read), nullptr); EXPECT_EQ(s.findRule("catalogX", KeyOp::Read), nullptr); } TEST(KeyScope, OriginAllowlist) { KeyScope s; EXPECT_TRUE(s.originAllowed("https://anything")); s.origins = {"https://konfig.megatoloajto.hu"}; EXPECT_TRUE(s.originAllowed("https://konfig.megatoloajto.hu")); EXPECT_FALSE(s.originAllowed("https://evil.example")); EXPECT_FALSE(s.originAllowed("")); } TEST(KeyScope, Expiry) { KeyScope s; EXPECT_FALSE(s.expired(1000)); s.expiresAt = 500; EXPECT_TRUE(s.expired(1000)); EXPECT_FALSE(s.expired(499)); } TEST(ApiKey, ScopeRoundTripsThroughJson) { ApiKey k; k.id = "k1"; k.key = "secretvalue"; k.projects = {"megatoloajto"}; KeyScope s; s.rules.push_back({"quotes", {KeyOp::Insert}, true}); s.origins = {"https://x"}; s.rateLimitPerMin = 120; s.expiresAt = 0; k.scope = s; ApiKey back = ApiKey::fromJson(k.toJson()); ASSERT_TRUE(back.scope.has_value()); ASSERT_NE(back.scope->findRule("quotes", KeyOp::Insert), nullptr); EXPECT_TRUE(back.scope->findRule("quotes", KeyOp::Insert)->requireHumanToken); EXPECT_EQ(back.scope->rateLimitPerMin, 120u); auto pub = k.toPublicJson(); EXPECT_TRUE(pub.contains("scope")); EXPECT_FALSE(pub.contains("key")); } TEST(ApiKey, NoScopeStaysAbsent) { ApiKey k; k.id = "k2"; EXPECT_FALSE(ApiKey::fromJson(k.toJson()).scope.has_value()); EXPECT_FALSE(k.toPublicJson().contains("scope")); }