Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Verified mods #262

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1146530
feat: add verifiedmods.cpp skeleton
Alystrasz Aug 30, 2022
36394d9
feat: add header file
Alystrasz Aug 30, 2022
b52f467
build: add verifiedmods files to solution
Alystrasz Aug 30, 2022
1ce0eb1
build: add header file to dllmain
Alystrasz Aug 30, 2022
ba63545
feat: add _FetchVerifiedModsList stupid implementation
Alystrasz Aug 30, 2022
be5b8dc
feat: use local variable to store mods list
Alystrasz Aug 31, 2022
09cb334
feat: add GetVerifiedModsList stupid implementation
Alystrasz Aug 31, 2022
1248906
feat: add wrapper method for GetVerifiedModsList method
Alystrasz Aug 31, 2022
5317e3e
build: add DLL load callback
Alystrasz Aug 31, 2022
264b524
Merge branch 'R2Northstar:main' into feat/verified-mods
Alystrasz Sep 2, 2022
2da03e4
fix: add masterserver header instead of source code file
Alystrasz Sep 6, 2022
983c52e
Merge branch 'feat/verified-mods' of github.com:Alystrasz/NorthstarLa…
Alystrasz Sep 6, 2022
7f75745
Check LSX for Origin launch (#263)
BobTheBob9 Sep 3, 2022
e1f1fb5
Merge branch 'main' into feat/verified-mods
Alystrasz Sep 6, 2022
90a0969
Merge branch 'feat/verified-mods' of github.com:Alystrasz/NorthstarLa…
Alystrasz Sep 6, 2022
4fc2083
build: include verifiedmods header in build
Alystrasz Sep 6, 2022
2fd87c0
fix: load library after client.dll load
Alystrasz Sep 6, 2022
588b564
fix: include header in source module
Alystrasz Sep 6, 2022
ee0715d
refactor: remove unused prototypes from module header
Alystrasz Sep 6, 2022
6144b95
Merge branch 'main' of github.com:Alystrasz/NorthstarLauncher
Alystrasz Sep 6, 2022
8091f06
Merge branch 'R2Northstar:main' into main
Alystrasz Sep 17, 2022
5e23bb1
Merge branch 'R2Northstar:main' into feat/verified-mods
Alystrasz Sep 17, 2022
e9b57ad
docs: add TODO notes
Alystrasz Sep 17, 2022
8de6698
feat: add IsModVerified method
Alystrasz Sep 17, 2022
08929ea
feat: add IsModVerified complete implementation
Alystrasz Sep 17, 2022
fb59e76
refactor: export mods test list outside fetching method
Alystrasz Sep 18, 2022
e7a473f
fix: IsModVerified correctly compares mod versions
Alystrasz Sep 18, 2022
91dec31
fix: strcmp returns 0 on valid comparison
Alystrasz Sep 18, 2022
5e20eda
Merge branch 'main' into feat/verified-mods
Alystrasz Nov 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NorthstarDLL/NorthstarDLL.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@
<ClInclude Include="exploitfixes.h" />
<ClInclude Include="exploitfixes_utf8parser.h" />
<ClInclude Include="nsmem.h" />
<ClInclude Include="verifiedmods.h" />
<ClInclude Include="version.h" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -629,6 +630,7 @@
<ClCompile Include="sourceinterface.cpp" />
<ClCompile Include="squirrel.cpp" />
<ClCompile Include="exploitfixes.cpp" />
<ClCompile Include="verifiedmods.cpp" />
<ClCompile Include="version.cpp" />
</ItemGroup>
<ItemGroup>
Expand Down
12 changes: 9 additions & 3 deletions NorthstarDLL/NorthstarDLL.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,9 @@
<ClInclude Include="scriptjson.h">
<Filter>Header Files\Shared</Filter>
</ClInclude>
<ClInclude Include="verifiedmods.h">
<Filter>Header Files\Client</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
Expand All @@ -1538,9 +1541,6 @@
<ClCompile Include="dedicated.cpp">
<Filter>Source Files\Server\Dedicated</Filter>
</ClCompile>
<ClCompile Include="sourceconsole.cpp">
<Filter>Source Files\Client</Filter>
</ClCompile>
<ClCompile Include="squirrel.cpp">
<Filter>Source Files\Shared</Filter>
</ClCompile>
Expand Down Expand Up @@ -1694,6 +1694,12 @@
<ClCompile Include="scriptutility.cpp">
<Filter>Source Files\Shared</Filter>
</ClCompile>
<ClCompile Include="sourceconsole.cpp">
<Filter>Source Files\Dedicated</Filter>
</ClCompile>
<ClCompile Include="verifiedmods.cpp">
<Filter>Source Files\Client</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm">
Expand Down
2 changes: 2 additions & 0 deletions NorthstarDLL/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "version.h"
#include "pch.h"
#include "scriptutility.h"
#include "verifiedmods.h"

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
Expand Down Expand Up @@ -243,6 +244,7 @@ bool InitialiseNorthstar()
AddDllLoadCallbackForClient("engine.dll", InitialiseChatCommands);
AddDllLoadCallbackForClient("client.dll", InitialiseScriptModMenu);
AddDllLoadCallbackForClient("client.dll", InitialiseScriptServerBrowser);
AddDllLoadCallbackForClient("client.dll", InitialiseVerifiedModsScripts);
AddDllLoadCallbackForClient("localize.dll", InitialiseModLocalisation);
AddDllLoadCallbackForClient("engine.dll", InitialiseClientAuthHooks);
AddDllLoadCallbackForClient("client.dll", InitialiseLatencyFleX);
Expand Down
169 changes: 169 additions & 0 deletions NorthstarDLL/verifiedmods.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#include "pch.h"
#include "masterserver.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "squirrel.h"
#include "verifiedmods.h"

using namespace rapidjson;

Document verifiedModsJson;

// Test string used to test branch without masterserver
const char* modsTestString =
"{"
"\"Dinorush's LTS Rebalance\" : {\"DependencyPrefix\" : \"Dinorush-LTSRebalance\", \"Versions\" : []}, "
"\"Dinorush.Brute4\" : {\"DependencyPrefix\" : \"Dinorush-Brute4\", \"Versions\" : [ \"1.5\", \"1.6\" ]}, "
"\"Mod Settings\" : {\"DependencyPrefix\" : \"EladNLG-ModSettings\", \"Versions\" : [ \"1.0.0\", \"1.1.0\" ]}, "
"\"Moblin.Archon\" : {\"DependencyPrefix\" : \"GalacticMoblin-MoblinArchon\", \"Versions\" : [ \"1.3.0\", \"1.3.1\" ]}"
"}";

void _FetchVerifiedModsList() {
spdlog::info("Requesting verified mods list from {}", Cvar_ns_masterserver_hostname->GetString());

std::thread requestThread([]() {
CURL* curl = curl_easy_init();

std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/verifiedmods", Cvar_ns_masterserver_hostname->GetString()).c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);

// TODO fetch list from masterserver
verifiedModsJson.Parse( modsTestString );
return;

CURLcode result = curl_easy_perform(curl);
spdlog::info(result);

if (result == CURLcode::CURLE_OK)
{
spdlog::info("curl succeeded");

verifiedModsJson.Parse(readBuffer.c_str());

if (verifiedModsJson.HasParseError())
{
spdlog::error("Failed reading masterserver verified mods response: encountered parse error.");
goto REQUEST_END_CLEANUP;
}
if (!verifiedModsJson.IsObject())
{
spdlog::error("Failed reading masterserver verified mods response: root object is not an object");
goto REQUEST_END_CLEANUP;
}
if (verifiedModsJson.HasMember("error"))
{
spdlog::error("Failed reading masterserver response: got fastify error response");
spdlog::error(readBuffer);
if (verifiedModsJson["error"].HasMember("enum"))
spdlog::error(std::string(verifiedModsJson["error"]["enum"].GetString()));
else
spdlog::error(std::string("No error message provided"));
goto REQUEST_END_CLEANUP;
}
}
else
{
spdlog::error("Failed requesting verified mods list: error {}", curl_easy_strerror(result));
}

REQUEST_END_CLEANUP:
curl_easy_cleanup(curl);
});
requestThread.detach();
}

std::string GetVerifiedModsList() {
if (verifiedModsJson.IsNull())
{
_FetchVerifiedModsList();

while (verifiedModsJson.IsNull())
{
spdlog::info("Wait for verified mods list to arrive...");
Sleep(2000); // TODO do this asynchronously to avoid blocking the thread
}

spdlog::info("Verified mods list arrived.");
}

StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
verifiedModsJson.Accept(writer);
return buffer.GetString();
}

/**
* Checks if a mod is verified by controlling if its name matches a key in the verified mods JSON
* document, and if its version is included in the JSON versions list.
*/
bool IsModVerified(char* modName, char* modVersion)
{
// 1. Mod is not verified if its name isn't a `verifiedModsJson` key.
if (!verifiedModsJson.HasMember(modName))
{
spdlog::info("Mod \"{}\" is not verified, and thus couldn't be downloaded.", modName);
return false;
}

// 2. Check if mod version has been validated.
const Value& entry = verifiedModsJson[modName];
GenericArray versions = entry["Versions"].GetArray();

spdlog::info("There's an entry for mod \"{}\", now checking version...", modName);

for (rapidjson::Value::ConstValueIterator iterator = versions.Begin(); iterator != versions.End(); iterator++)
{
const rapidjson::Value& version = *iterator;
if (strcmp(version.GetString(), modVersion) == 0)
{
spdlog::info("Mod \"{}\" (version {}) is verified.", modName, modVersion);
return true;
}
}

spdlog::info("Required version {} for mod \"{}\" is not verified, and thus couldn't be downloaded.", modVersion, modName);
return false;
}

void DownloadMod(char* modName, char* modVersion) {
if (!IsModVerified(modName, modVersion))
return;

// TODO check if mod is already present
// TODO check if mod is verified (throw if not)
// TODO download zip in temporary folder
// TODO move mod to mods/ folder
}



/**
* Squirrel-exposed wrapper methods
**/

SQRESULT SQ_GetVerifiedModsList(void* sqvm)
{
std::string mods = GetVerifiedModsList();
const SQChar* buffer = mods.c_str();
ClientSq_pushstring(sqvm, buffer, -1);
return SQRESULT_NOTNULL;
}

SQRESULT SQ_IsModVerified(void* sqvm)
{
const SQChar* modName = ClientSq_getstring(sqvm, 1);
const SQChar* modVersion = ClientSq_getstring(sqvm, 2);

bool result = IsModVerified((char*)modName, (char*)modVersion);

ClientSq_pushbool(sqvm, result);
return SQRESULT_NOTNULL;
}

void InitialiseVerifiedModsScripts(HMODULE baseAddress) {
g_UISquirrelManager->AddFuncRegistration("string", "GetVerifiedModsList", "", "", SQ_GetVerifiedModsList);
g_UISquirrelManager->AddFuncRegistration("bool", "IsModVerified", "string modName, string modVersion", "", SQ_IsModVerified);
}
4 changes: 4 additions & 0 deletions NorthstarDLL/verifiedmods.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include "memalloc.h"

void InitialiseVerifiedModsScripts(HMODULE baseAddress);