diff --git a/src/shared/revision_data.h.in b/src/shared/revision_data.h.in index a5d048931..60a852857 100644 --- a/src/shared/revision_data.h.in +++ b/src/shared/revision_data.h.in @@ -56,8 +56,8 @@ #define WORLD_DB_VERSION_NR "22" #define WORLD_DB_STRUCTURE_NR "6" - #define WORLD_DB_CONTENT_NR "3" - #define WORLD_DB_UPDATE_DESCRIPT "Warden_Checks" + #define WORLD_DB_CONTENT_NR "4" + #define WORLD_DB_UPDATE_DESCRIPT "Warden_Locale_Hardening" #define VER_COMPANY_NAME_STR "MaNGOS Developers" #define VER_LEGALCOPYRIGHT_STR "(c)2005-@rev_year@ MaNGOS" diff --git a/src/tests/DatabaseVersionTest.cpp b/src/tests/DatabaseVersionTest.cpp index a8b4672e8..35eb33e22 100644 --- a/src/tests/DatabaseVersionTest.cpp +++ b/src/tests/DatabaseVersionTest.cpp @@ -39,6 +39,7 @@ TEST(CoreDatabaseVersion_requires_database_backed_warden_catalogue) CHECK_STR(GitRevision::GetWorldDBVersion(), "22"); CHECK_STR(GitRevision::GetWorldDBStructure(), "6"); - CHECK_STR(GitRevision::GetWorldDBContent(), "3"); - CHECK_STR(GitRevision::GetWorldDBUpdateDescription(), "Warden_Checks"); + CHECK_STR(GitRevision::GetWorldDBContent(), "4"); + CHECK_STR(GitRevision::GetWorldDBUpdateDescription(), + "Warden_Locale_Hardening"); } diff --git a/src/tests/WardenCheckCatalogTest.cpp b/src/tests/WardenCheckCatalogTest.cpp index 9ce131e68..ed56b71ef 100644 --- a/src/tests/WardenCheckCatalogTest.cpp +++ b/src/tests/WardenCheckCatalogTest.cpp @@ -67,12 +67,12 @@ std::vector FirstProfileRows() { std::vector rows = warden::test::InitialWardenRows(); - rows.resize(7); + rows.resize(9); return rows; } } -TEST(WardenCheckCatalog_decodes_and_selects_three_exact_profiles) +TEST(WardenCheckCatalog_decodes_and_selects_eight_exact_profiles) { warden::WardenCheckCatalogBuilder builder; warden::WardenCheckDiagnostic diagnostic; @@ -86,21 +86,94 @@ TEST(WardenCheckCatalog_decodes_and_selects_three_exact_profiles) warden::WardenCheckCatalog catalog; REQUIRE(builder.Build(catalog, diagnostic) == warden::CheckCatalogValidation::Valid); - CHECK_EQ(catalog.TotalRows(), uint32(21)); - CHECK_EQ(catalog.EnabledRows(), uint32(21)); - CHECK_EQ(catalog.Profiles().size(), size_t(3)); + CHECK_EQ(catalog.TotalRows(), uint32(72)); + CHECK_EQ(catalog.EnabledRows(), uint32(72)); + CHECK_EQ(catalog.Profiles().size(), size_t(8)); + + struct ProfileExpectation + { + uint32 build; + char const* locale; + char const* mpqSha1; + char const* luaText; + uint32 frameDispatchAddress; + char const* frameDispatchBytes; + }; + ProfileExpectation const profiles[] = + { + {5875, "enUS", "7d88154d3411811985f5d81177c5453248133443", + "4f6b6179", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {5875, "koKR", "755d6d7f49bb34114433386d559261ed3aa23f00", + "ed9995ec9db8", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {5875, "zhTW", "2a70e6402a40a4f9e9960ced419dba5e6deb8536", + "e7a2bae5ae9a", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {5875, "frFR", "af2d81af013a9ba6bb92ce171e43fa903c9e8c09", + "4f4b", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {5875, "esES", "1ecec2c6596b8411fa5fe153edfb9a6ee43360e9", + "41636570746172", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {6005, "enGB", "7d88154d3411811985f5d81177c5453248133443", + "4f6b6179", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {6005, "deDE", "a0b3dc2d78ad892f2436bcd937be51b4989d64c1", + "4f4b", 4784584, + "5eff48006bff480078ff480095ff4800"}, + {6141, "zhCN", "c5a1de4c1cd412eb4d2e02afab6131b737efcaf0", + "e7a1aee5ae9a", 4788152, + "4e0d49005b0d4900680d4900850d4900"} + }; + uint32 const expectedIds[] = + {65536, 1, 2, 1107, 827, 1566, 1135, 65537, 65538}; + + for (ProfileExpectation const& expected : profiles) + { + warden::WardenCheckProfile const* profile = + catalog.Find(expected.build, "Win", expected.locale); + REQUIRE(profile != nullptr); + REQUIRE(profile->checks.size() == 9u); + CHECK(profile->hasActionableChecks); + CHECK_EQ(profile->totalRows, uint32(9)); + for (size_t index = 0; index < 9u; ++index) + { + CHECK_EQ(warden::GetWardenCheckId(profile->checks[index]), + expectedIds[index]); + } + + CHECK(warden::GetWardenCheckType(profile->checks[0]) == + warden::WardenCheckType::Timing); + CHECK(!warden::IsConfirmationEligible(profile->checks[0])); + CHECK(warden::IsConfirmationEligible(profile->checks[1])); + + warden::MpqCheckProfile const& mpq = + std::get(profile->checks[1].payload); + CHECK_HEX(mpq.expectedSha1.data(), mpq.expectedSha1.size(), + expected.mpqSha1); + warden::LuaCheckProfile const& lua = + std::get(profile->checks[2].payload); + CHECK_HEX(reinterpret_cast(lua.expectedText.data()), + lua.expectedText.size(), expected.luaText); + + warden::MemCheckProfile const& glue = + std::get(profile->checks[7].payload); + CHECK_EQ(glue.addressOrRva, uint32(4631212)); + CHECK_HEX(glue.expectedBytes.data(), glue.expectedBytes.size(), + "1ca9460029a9460036a946009ea94600"); + CHECK(profile->checks[7].evidenceClass == + warden::WardenEvidenceClass::IntegrityInvariant); + + warden::MemCheckProfile const& frame = + std::get(profile->checks[8].payload); + CHECK_EQ(frame.addressOrRva, expected.frameDispatchAddress); + CHECK_HEX(frame.expectedBytes.data(), frame.expectedBytes.size(), + expected.frameDispatchBytes); + CHECK(profile->checks[8].evidenceClass == + warden::WardenEvidenceClass::IntegrityInvariant); + } - warden::WardenCheckProfile const* profile = - catalog.Find(6141, "Win", "zhCN"); - REQUIRE(profile != nullptr); - REQUIRE(profile->checks.size() == 7u); - CHECK(profile->hasActionableChecks); - CHECK_EQ(profile->totalRows, uint32(7)); - CHECK_EQ(warden::GetWardenCheckId(profile->checks[0]), uint32(65536)); - CHECK(warden::GetWardenCheckType(profile->checks[0]) == - warden::WardenCheckType::Timing); - CHECK(!warden::IsConfirmationEligible(profile->checks[0])); - CHECK(warden::IsConfirmationEligible(profile->checks[1])); CHECK(warden::IsActionableEvidenceClass( warden::WardenEvidenceClass::IntegrityInvariant)); CHECK(warden::IsActionableEvidenceClass( @@ -110,12 +183,7 @@ TEST(WardenCheckCatalog_decodes_and_selects_three_exact_profiles) CHECK(!warden::IsActionableEvidenceClass( warden::WardenEvidenceClass::Corroboration)); - warden::LuaCheckProfile const& lua = - std::get(profile->checks[2].payload); - CHECK_HEX(reinterpret_cast(lua.expectedText.data()), - lua.expectedText.size(), "e7a1aee5ae9a"); - CHECK(catalog.Find(5875, "Win", "enUS") != nullptr); - CHECK(catalog.Find(6005, "Win", "enGB") != nullptr); + CHECK(catalog.Find(5875, "Win", "itIT") == nullptr); CHECK(catalog.Find(6005, "Win", "enUS") == nullptr); CHECK(catalog.Find(6141, "OSX", "zhCN") == nullptr); } @@ -239,7 +307,7 @@ TEST(WardenCheckCatalog_enforces_timing_contract_and_cardinality) CHECK(BuildRows(rows) == warden::CheckCatalogValidation::DisabledTiming); rows = FirstProfileRows(); warden::WardenCheckRowInput secondTiming = rows[0]; - secondTiming.checkId = 65537; + secondTiming.checkId = 65539; secondTiming.sortOrder = 11; rows.push_back(secondTiming); CHECK(BuildRows(rows) == warden::CheckCatalogValidation::MultipleTiming); @@ -523,12 +591,12 @@ TEST(WardenCheckCatalog_enforces_complete_profiles_and_atomic_build) warden::WardenCheckCatalog unchanged = warden::test::BuildInitialWardenCatalog(); - REQUIRE(unchanged.TotalRows() == 21u); + REQUIRE(unchanged.TotalRows() == 72u); rows = FirstProfileRows(); rows[2].checkId = rows[1].checkId; CHECK(BuildRows(rows, unchanged) == warden::CheckCatalogValidation::DuplicateId); - CHECK_EQ(unchanged.TotalRows(), uint32(21)); + CHECK_EQ(unchanged.TotalRows(), uint32(72)); CHECK(unchanged.Find(6141, "Win", "zhCN") != nullptr); } diff --git a/src/tests/WardenCheckFixtures.h b/src/tests/WardenCheckFixtures.h index 105e51721..9a7b092c5 100644 --- a/src/tests/WardenCheckFixtures.h +++ b/src/tests/WardenCheckFixtures.h @@ -53,7 +53,8 @@ inline void AppendInitialProfile(std::vector& rows, std::string const& mpqExpectedHex, std::string const& luaExpectedHex, uint32 functionAddress, std::string const& functionExpectedHex, uint32 flagsAddress, uint32 luaProtectionAddress, - std::string const& luaProtectionExpectedHex, uint32 wallClimbAddress) + std::string const& luaProtectionExpectedHex, uint32 wallClimbAddress, + uint32 frameDispatchAddress, std::string const& frameDispatchExpectedHex) { rows.push_back(MakeRow(build, localeHex, 65536, WardenCheckType::Timing, 10, WardenEvidenceClass::ProtocolHealth)); @@ -98,28 +99,77 @@ inline void AppendInitialProfile(std::vector& rows, wallClimb.length = 4; wallClimb.expectedHex = "BB8D243F"; rows.push_back(wallClimb); + + // Both tables dispatch the client interface-signature result. A patched + // table can turn all outcomes into success without changing Warden code. + WardenCheckRowInput glueDispatch = MakeRow(build, localeHex, 65537, + WardenCheckType::Mem, 80, WardenEvidenceClass::IntegrityInvariant); + glueDispatch.address = 4631212; + glueDispatch.length = 16; + glueDispatch.expectedHex = "1CA9460029A9460036A946009EA94600"; + rows.push_back(glueDispatch); + + WardenCheckRowInput frameDispatch = MakeRow(build, localeHex, 65538, + WardenCheckType::Mem, 90, WardenEvidenceClass::IntegrityInvariant); + frameDispatch.address = frameDispatchAddress; + frameDispatch.length = 16; + frameDispatch.expectedHex = frameDispatchExpectedHex; + rows.push_back(frameDispatch); } -/** Exact database rows intended for the first three supported profiles. */ +/** Exact database rows intended for all supported Classic Windows profiles. */ inline std::vector InitialWardenRows() { std::vector rows; - rows.reserve(21); + rows.reserve(72); AppendInitialProfile(rows, 5875, "656E5553", "7D88154D3411811985F5D81177C5453248133443", "4F6B6179", 6392064, "558BEC8B51408B450C81E2FF7DA075508950108B450850E824DA1A005DC20800", - 8151558, 4803152, "A1C0EACE00", 8445948); + 8151558, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); + AppendInitialProfile(rows, 5875, "6B6F4B52", + "755D6D7F49BB34114433386D559261ED3AA23F00", "ED9995EC9DB8", + 6392064, + "558BEC8B51408B450C81E2FF7DA075508950108B450850E824DA1A005DC20800", + 8151558, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); + AppendInitialProfile(rows, 5875, "7A685457", + "2A70E6402A40A4F9E9960CED419DBA5E6DEB8536", "E7A2BAE5AE9A", + 6392064, + "558BEC8B51408B450C81E2FF7DA075508950108B450850E824DA1A005DC20800", + 8151558, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); + AppendInitialProfile(rows, 5875, "66724652", + "AF2D81AF013A9BA6BB92CE171E43FA903C9E8C09", "4F4B", + 6392064, + "558BEC8B51408B450C81E2FF7DA075508950108B450850E824DA1A005DC20800", + 8151558, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); + AppendInitialProfile(rows, 5875, "65734553", + "1ECEC2C6596B8411FA5FE153EDFB9A6EE43360E9", "41636570746172", + 6392064, + "558BEC8B51408B450C81E2FF7DA075508950108B450850E824DA1A005DC20800", + 8151558, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); AppendInitialProfile(rows, 6005, "656E4742", "7D88154D3411811985F5D81177C5453248133443", "4F6B6179", 6392064, "558BEC8B51408B450C81E2FF7DA075508950108B450850E864DA1A005DC20800", - 8151622, 4803152, "A1C0EACE00", 8445948); + 8151622, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); + AppendInitialProfile(rows, 6005, "64654445", + "A0B3DC2D78AD892F2436BCD937BE51B4989D64C1", "4F4B", + 6392064, + "558BEC8B51408B450C81E2FF7DA075508950108B450850E864DA1A005DC20800", + 8151622, 4803152, "A1C0EACE00", 8445948, 4784584, + "5EFF48006BFF480078FF480095FF4800"); AppendInitialProfile(rows, 6141, "7A68434E", "C5A1DE4C1CD412EB4D2E02AFAB6131B737EFCAF0", "E7A1AEE5AE9A", 6401184, "558BEC8B51408B450C81E2FF7DA075508950108B450850E864EB1A005DC20800", - 8165094, 4806720, "A1E031CF00", 8462780); + 8165094, 4806720, "A1E031CF00", 8462780, 4788152, + "4E0D49005B0D4900680D4900850D4900"); return rows; } diff --git a/src/tests/WardenCheckPlannerTest.cpp b/src/tests/WardenCheckPlannerTest.cpp index 19aea3b87..fe4a1360a 100644 --- a/src/tests/WardenCheckPlannerTest.cpp +++ b/src/tests/WardenCheckPlannerTest.cpp @@ -158,7 +158,7 @@ TEST(WardenCheckPlanner_profileless_planner_remains_inert) TEST(WardenCheckPlanner_initial_plan_waits_and_preserves_catalogue_order) { std::vector const checks = ExactChecks(); - REQUIRE(checks.size() == 7u); + REQUIRE(checks.size() == 9u); warden::WardenCheckPlanner planner(warden::WardenConfiguration{}, 1000, checks); @@ -169,11 +169,11 @@ TEST(WardenCheckPlanner_initial_plan_waits_and_preserves_catalogue_order) REQUIRE(plan.has_value()); CHECK_EQ(plan->requestId, uint32(1)); CHECK(plan->purpose == warden::CheckPlanPurpose::Initial); - REQUIRE(plan->checks.size() == 7u); + REQUIRE(plan->checks.size() == 9u); for (size_t index = 1; index < plan->checks.size(); ++index) CHECK(plan->checks[index - 1].sortOrder < plan->checks[index].sortOrder); CHECK_EQ(warden::GetWardenCheckId(plan->checks.front()), uint32(65536)); - CHECK_EQ(warden::GetWardenCheckId(plan->checks.back()), uint32(1135)); + CHECK_EQ(warden::GetWardenCheckId(plan->checks.back()), uint32(65538)); CHECK(!planner.Update(true, 60000).has_value()); } @@ -189,7 +189,7 @@ TEST(WardenCheckPlanner_resets_partial_initial_delay_when_ineligible) TEST(WardenCheckPlanner_normal_rotation_covers_every_nonhealth_check_once) { - ScriptedRandom random{{30, 30, 30, 30}, {}, {}}; + ScriptedRandom random{{30, 30, 30, 30, 30}, {}, {}}; warden::WardenCheckPlanner planner(warden::WardenConfiguration{}, 1000, ExactChecks(), random.Callback()); std::optional initial = planner.Update(true, 1000); @@ -197,7 +197,7 @@ TEST(WardenCheckPlanner_normal_rotation_covers_every_nonhealth_check_once) planner.Complete(*initial); std::map counts; - for (uint32 batch = 0; batch < 3; ++batch) + for (uint32 batch = 0; batch < 4; ++batch) { std::optional recurring = planner.Update(true, 30000); @@ -216,9 +216,9 @@ TEST(WardenCheckPlanner_normal_rotation_covers_every_nonhealth_check_once) planner.Complete(*recurring); } - CHECK_EQ(counts.size(), size_t(6)); + CHECK_EQ(counts.size(), size_t(8)); for (uint32 id : {uint32(1), uint32(2), uint32(1107), uint32(827), - uint32(1566), uint32(1135)}) + uint32(1566), uint32(1135), uint32(65537), uint32(65538)}) CHECK_EQ(counts[id], uint32(1)); } @@ -275,7 +275,7 @@ TEST(WardenCheckPlanner_aggressive_plans_include_only_actionable_checks) CHECK(immediate->purpose == warden::CheckPlanPurpose::AggressiveImmediate); CHECK(CheckIds(*immediate) == - std::vector({1107, 827, 1566})); + std::vector({1107, 827, 1566, 65537, 65538})); planner.Complete(*immediate); std::optional initial = planner.Update(true, 1000); @@ -287,7 +287,7 @@ TEST(WardenCheckPlanner_aggressive_plans_include_only_actionable_checks) CHECK(recurring->purpose == warden::CheckPlanPurpose::AggressiveRecurring); CHECK(CheckIds(*recurring) == - std::vector({1107, 827, 1566})); + std::vector({1107, 827, 1566, 65537, 65538})); } TEST(WardenCheckPlanner_observation_only_aggressive_mode_uses_normal_checks) @@ -354,10 +354,10 @@ TEST(WardenCheckPlanner_preflight_is_linear_and_uses_exact_purposes) REQUIRE(exact != nullptr); std::vector plans = warden::BuildWardenPreflightPlans(*exact); - REQUIRE(plans.size() == 7u); + REQUIRE(plans.size() == 9u); CHECK(plans[0].purpose == warden::CheckPlanPurpose::Initial); CHECK_EQ(plans[0].requestId, uint32(1)); - CHECK_EQ(plans[0].checks.size(), size_t(7)); + CHECK_EQ(plans[0].checks.size(), size_t(9)); for (size_t index = 1; index < plans.size(); ++index) { CHECK(plans[index].purpose == diff --git a/src/tests/WardenModuleCatalogTest.cpp b/src/tests/WardenModuleCatalogTest.cpp index c04c0e8da..724b3ce03 100644 --- a/src/tests/WardenModuleCatalogTest.cpp +++ b/src/tests/WardenModuleCatalogTest.cpp @@ -91,7 +91,7 @@ TEST(WardenCatalog_coverage_requires_profiles_and_modules_both_directions) std::vector rows = warden::test::InitialWardenRows(); - rows.resize(7); + rows.resize(9); warden::WardenCheckCatalog missingModule = BuildCheckCatalog(rows); CHECK(warden::ValidateWardenCatalogCoverage(missingModule, modules) == warden::WardenCheckCatalogLoadFailure::ModuleWithoutProfile); diff --git a/src/tests/WardenPacketCodecTest.cpp b/src/tests/WardenPacketCodecTest.cpp index 17eb27a52..1f449d75f 100644 --- a/src/tests/WardenPacketCodecTest.cpp +++ b/src/tests/WardenPacketCodecTest.cpp @@ -324,11 +324,14 @@ TEST(WardenPacket_encodes_exact_crossbuild_timing_and_mem_requests) Vector const vectors[] = { {5875, "enUS", - "0200288c0000896100208c0006627c000d8c00504a4900058c00fcdf8000047f"}, + "0200288c0000896100208c0006627c000d8c00504a4900058c00fcdf800004" + "8c00acaa4600108c00c8014900107f"}, {6005, "enGB", - "0200288c0000896100208c0046627c000d8c00504a4900058c00fcdf8000047f"}, + "0200288c0000896100208c0046627c000d8c00504a4900058c00fcdf800004" + "8c00acaa4600108c00c8014900107f"}, {6141, "zhCN", - "0200288c00a0ac6100208c00e6967c000d8c0040584900058c00bc218100047f"} + "0200288c00a0ac6100208c00e6967c000d8c0040584900058c00bc21810004" + "8c00acaa4600108c00b80f4900107f"} }; for (Vector const& vector : vectors) @@ -505,17 +508,20 @@ TEST(WardenPacket_decodes_exact_crossbuild_mem_result_vectors) Vector const vectors[] = { {5875, "enUS", - "023f00833bdafb010403020100558bec8b51408b450c81e2ff7da07550" + "0261000ff23245010403020100558bec8b51408b450c81e2ff7da07550" "8950108b450850e824da1a005dc208000025ffffdffb0d00200000894640" - "00a1c0eace0000bb8d243f"}, + "00a1c0eace0000bb8d243f001ca9460029a9460036a946009ea94600" + "005eff48006bff480078ff480095ff4800"}, {6005, "enGB", - "023f0053b1b911010403020100558bec8b51408b450c81e2ff7da07550" + "026100d90dfed3010403020100558bec8b51408b450c81e2ff7da07550" "8950108b450850e864da1a005dc208000025ffffdffb0d00200000894640" - "00a1c0eace0000bb8d243f"}, + "00a1c0eace0000bb8d243f001ca9460029a9460036a946009ea94600" + "005eff48006bff480078ff480095ff4800"}, {6141, "zhCN", - "023f0099e39fee010403020100558bec8b51408b450c81e2ff7da07550" + "02610060124e86010403020100558bec8b51408b450c81e2ff7da07550" "8950108b450850e864eb1a005dc208000025ffffdffb0d00200000894640" - "00a1e031cf0000bb8d243f"} + "00a1e031cf0000bb8d243f001ca9460029a9460036a946009ea94600" + "004e0d49005b0d4900680d4900850d4900"} }; for (Vector const& vector : vectors) @@ -525,9 +531,9 @@ TEST(WardenPacket_decodes_exact_crossbuild_mem_result_vectors) REQUIRE(warden::DecodeCheckResult(View(response), TimingMemPlan(vector.build, vector.locale), result) == warden::DecodeStatus::Ok); - REQUIRE(result.checks.size() == 5u); - size_t const expectedSizes[] = {32u, 13u, 5u, 4u}; - for (size_t index = 0; index < 4u; ++index) + REQUIRE(result.checks.size() == 7u); + size_t const expectedSizes[] = {32u, 13u, 5u, 4u, 16u, 16u}; + for (size_t index = 0; index < 6u; ++index) { REQUIRE(std::holds_alternative( result.checks[index + 1u])); @@ -539,11 +545,11 @@ TEST(WardenPacket_decodes_exact_crossbuild_mem_result_vectors) } warden::Bytes const unavailable = - FromHex("0209005848324d010403020101010101"); + FromHex("020b00f49e5b190104030201010101010101"); warden::CheckBatchResult result; REQUIRE(warden::DecodeCheckResult(View(unavailable), TimingMemPlan(5875, "enUS"), result) == warden::DecodeStatus::Ok); - REQUIRE(result.checks.size() == 5u); + REQUIRE(result.checks.size() == 7u); for (size_t index = 1; index < result.checks.size(); ++index) { warden::MemResult const& mem = @@ -1014,7 +1020,7 @@ TEST(WardenPacket_inspects_plan_identity_and_confirmation_contracts) warden::CheckPlanValidation::DuplicateCheckId); plan.checks = profile->checks; warden::WardenCheckDefinition secondTiming = plan.checks[0]; - std::get(secondTiming.payload).checkId = 65537; + std::get(secondTiming.payload).checkId = 65539; secondTiming.sortOrder = 11; plan.checks.push_back(secondTiming); CHECK(warden::InspectCheckPlan(plan, budget) == diff --git a/src/tests/WardenServerTest.cpp b/src/tests/WardenServerTest.cpp index f8ab9836c..b4af88adc 100644 --- a/src/tests/WardenServerTest.cpp +++ b/src/tests/WardenServerTest.cpp @@ -476,6 +476,7 @@ bool StartTimingMpqLuaMemCheck(Harness& harness) "7265615461626C652E646263044F4B4159" "0028E701F4028C0000896100208C000662" "7C000D8C00504A4900058C00FCDF800004" + "8C00ACAA4600108C00C801490010" "7F"); } @@ -739,37 +740,37 @@ TEST(WardenManager_creation_is_inert_for_exact_builds_and_rejects_unknown_ones) return true; }; - std::unique_ptr supported = - warden::WardenManager::Instance().Create(5875, "Win", "enUS", - TestSessionKey(), send); - REQUIRE(supported != nullptr); - CHECK_EQ(calls, 0u); - CHECK(supported->Start()); - CHECK_EQ(calls, 1u); - CHECK(supported->Start()); - CHECK_EQ(calls, 1u); - - std::unique_ptr supported6005 = - warden::WardenManager::Instance().Create(6005, "Win", "enGB", - TestSessionKey(), send); - REQUIRE(supported6005 != nullptr); - CHECK_EQ(calls, 1u); - CHECK(supported6005->Start()); - CHECK_EQ(calls, 2u); + struct Profile + { + uint32 build; + char const* locale; + }; + Profile const profiles[] = + { + {5875, "enUS"}, {5875, "koKR"}, {5875, "zhTW"}, + {5875, "frFR"}, {5875, "esES"}, {6005, "enGB"}, + {6005, "deDE"}, {6141, "zhCN"} + }; - std::unique_ptr supported6141 = - warden::WardenManager::Instance().Create(6141, "Win", "zhCN", - TestSessionKey(), send); - REQUIRE(supported6141 != nullptr); - CHECK_EQ(calls, 2u); - CHECK(supported6141->Start()); - CHECK_EQ(calls, 3u); + for (Profile const& profile : profiles) + { + std::unique_ptr supported = + warden::WardenManager::Instance().Create(profile.build, "Win", + profile.locale, TestSessionKey(), send); + REQUIRE(supported != nullptr); + CHECK_EQ(calls, 0u); + CHECK(supported->Start()); + CHECK_EQ(calls, 1u); + CHECK(supported->Start()); + CHECK_EQ(calls, 1u); + calls = 0; + } std::unique_ptr unsupported = warden::WardenManager::Instance().Create(9999, "Win", "enUS", TestSessionKey(), send); CHECK(unsupported == nullptr); - CHECK_EQ(calls, 3u); + CHECK_EQ(calls, 0u); } TEST(WardenManager_publishes_one_immutable_check_catalogue_snapshot) @@ -793,26 +794,29 @@ TEST(WardenManager_publishes_one_immutable_check_catalogue_snapshot) warden::WardenCheckProfile const* selected = manager.FindCheckProfile(5875, "Win", "enUS"); REQUIRE(selected != nullptr); - CHECK_EQ(selected->checks.size(), size_t(7)); + CHECK_EQ(selected->checks.size(), size_t(9)); CHECK(!manager.PublishCheckCatalog(empty)); CHECK(!manager.PublishCheckCatalog(second)); CHECK(manager.FindCheckProfile(5875, "Win", "enUS") == selected); } -TEST(WardenManager_selects_content_checks_only_for_the_exact_locale) +TEST(WardenManager_selects_content_checks_for_supported_exact_locales_only) { Harness enUS(ManagerLocale{"enUS"}); REQUIRE(StartTimingMpqLuaMemCheck(enUS)); + Harness frFR(ManagerLocale{"frFR"}); + REQUIRE(StartTimingMpqLuaMemCheck(frFR)); + warden::WardenCreationOptions observe; observe.configuration.enforcementMode = warden::WardenEnforcementMode::Observe; - Harness frFR(ManagerLocale{"frFR"}, true, observe); - REQUIRE(ReachModuleReady(frFR)); - frFR.server->Update(true, 60000); - CHECK(frFR.server->GetState() == warden::WardenState::ModuleReady); - CHECK_EQ(frFR.sent.size(), size_t(3)); - CHECK(frFR.evidenceEvents.empty()); + Harness itIT(ManagerLocale{"itIT"}, true, observe); + REQUIRE(ReachModuleReady(itIT)); + itIT.server->Update(true, 60000); + CHECK(itIT.server->GetState() == warden::WardenState::ModuleReady); + CHECK_EQ(itIT.sent.size(), size_t(3)); + CHECK(itIT.evidenceEvents.empty()); } TEST(WardenManager_enforcing_modes_require_exact_check_profiles) @@ -827,9 +831,14 @@ TEST(WardenManager_enforcing_modes_require_exact_check_profiles) }; Profile const profiles[] = { - {5875, "enUS", "frFR"}, - {6005, "enGB", "enUS"}, - {6141, "zhCN", "enUS"} + {5875, "enUS", "itIT"}, + {5875, "koKR", "itIT"}, + {5875, "zhTW", "itIT"}, + {5875, "frFR", "itIT"}, + {5875, "esES", "itIT"}, + {6005, "enGB", "itIT"}, + {6005, "deDE", "itIT"}, + {6141, "zhCN", "itIT"} }; for (warden::WardenEnforcementMode mode : @@ -857,7 +866,7 @@ TEST(WardenManager_observe_mode_allows_missing_check_profile) options.configuration.enforcementMode = warden::WardenEnforcementMode::Observe; - CHECK(warden::WardenManager::Instance().Create(5875, "Win", "frFR", + CHECK(warden::WardenManager::Instance().Create(5875, "Win", "itIT", TestSessionKey(), [](warden::Bytes const&) { return true; }, options) != nullptr); } @@ -866,10 +875,15 @@ TEST(WardenManager_identifies_only_exact_enforcement_profiles) { REQUIRE(EnsureTestCatalogPublished()); CHECK(warden::IsWardenEnforcementProfile(5875, "Win", "enUS")); + CHECK(warden::IsWardenEnforcementProfile(5875, "Win", "koKR")); + CHECK(warden::IsWardenEnforcementProfile(5875, "Win", "zhTW")); + CHECK(warden::IsWardenEnforcementProfile(5875, "Win", "frFR")); + CHECK(warden::IsWardenEnforcementProfile(5875, "Win", "esES")); CHECK(warden::IsWardenEnforcementProfile(6005, "Win", "enGB")); + CHECK(warden::IsWardenEnforcementProfile(6005, "Win", "deDE")); CHECK(warden::IsWardenEnforcementProfile(6141, "Win", "zhCN")); - CHECK(!warden::IsWardenEnforcementProfile(5875, "Win", "enGB")); + CHECK(!warden::IsWardenEnforcementProfile(5875, "Win", "itIT")); CHECK(!warden::IsWardenEnforcementProfile(6005, "Win", "enUS")); CHECK(!warden::IsWardenEnforcementProfile(6141, "Win", "enUS")); CHECK(!warden::IsWardenEnforcementProfile(5875, "OSX", "enUS"));