feat: implement rest of endpoints
This commit is contained in:
+423
-9
@@ -2,6 +2,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "log-sink.h"
|
#include "log-sink.h"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <map>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <tinymitm/proxy.h>
|
#include <tinymitm/proxy.h>
|
||||||
@@ -13,8 +15,22 @@
|
|||||||
|
|
||||||
#include <glaze/glaze.hpp>
|
#include <glaze/glaze.hpp>
|
||||||
|
|
||||||
#include <map>
|
/*
|
||||||
|
misc helper functions
|
||||||
|
*/
|
||||||
|
std::unordered_set<std::string> slasherNames = {
|
||||||
|
"Chuckles", "Bob", "HillBilly", "Nurse", "Shape", "Witch", "Killer07", "Cannibal", "Bear",
|
||||||
|
"Nightmare", "Pig", "Clown", "Spirit", "Plague", "Ghostface", "Demogorgon", "Oni", "Gunslinger"};
|
||||||
|
|
||||||
|
bool isSlasher(std::string name)
|
||||||
|
{
|
||||||
|
if (slasherNames.contains(name) || (name.length() == 3 && name[0] == 'K')) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
spoofer impl
|
||||||
|
*/
|
||||||
Spoofer::Spoofer()
|
Spoofer::Spoofer()
|
||||||
{
|
{
|
||||||
_log = new seallib::Logger("Spoofer");
|
_log = new seallib::Logger("Spoofer");
|
||||||
@@ -239,6 +255,290 @@ void Spoofer::wsMessageCallback(std::shared_ptr<ix::ConnectionState> /*connectio
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
endpoint related helper functions
|
||||||
|
*/
|
||||||
|
void Spoofer::modifyCharacterInventory(glz::generic& js)
|
||||||
|
{
|
||||||
|
bool slasher = isSlasher(js["characterName"].get<std::string>());
|
||||||
|
|
||||||
|
bool hasItems = js.is_object() && js.get_object().contains("characterItems") && js["characterItems"].is_array();
|
||||||
|
if (!hasItems) return;
|
||||||
|
|
||||||
|
std::unordered_set<std::string> existingItemIds;
|
||||||
|
std::unordered_map<std::string, int> stackableQty;
|
||||||
|
stackableQty.insert(_camperItems.begin(), _camperItems.end());
|
||||||
|
stackableQty.insert(_camperOfferings.begin(), _camperOfferings.end());
|
||||||
|
stackableQty.insert(_globalOfferings.begin(), _globalOfferings.end());
|
||||||
|
stackableQty.insert(_camperAddons.begin(), _camperAddons.end());
|
||||||
|
stackableQty.insert(_slasherAddons.begin(), _slasherAddons.end());
|
||||||
|
stackableQty.insert(_slasherOfferings.begin(), _slasherOfferings.end());
|
||||||
|
|
||||||
|
auto& itemsArr = js["characterItems"].get_array();
|
||||||
|
|
||||||
|
/*
|
||||||
|
existing items
|
||||||
|
*/
|
||||||
|
for (auto& item : itemsArr)
|
||||||
|
{
|
||||||
|
if (item.is_object() && item.get_object().contains("itemId") && item["itemId"].is_string())
|
||||||
|
{
|
||||||
|
std::string itemId = item["itemId"].get<std::string>();
|
||||||
|
existingItemIds.insert(itemId);
|
||||||
|
auto it = stackableQty.find(itemId);
|
||||||
|
if (it != stackableQty.end()) item["quantity"] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
item injection
|
||||||
|
*/
|
||||||
|
auto appendItems = [&](const std::unordered_map<std::string, int>& idMap) {
|
||||||
|
for (const auto& [itemId, qty] : idMap)
|
||||||
|
if (existingItemIds.find(itemId) == existingItemIds.end())
|
||||||
|
{
|
||||||
|
glz::json_t::object_t newItem;
|
||||||
|
newItem["itemId"] = itemId;
|
||||||
|
newItem["quantity"] = qty;
|
||||||
|
itemsArr.push_back(newItem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto appendPerks = [&](const std::unordered_set<std::string>& idSet) {
|
||||||
|
for (const auto& itemId : idSet)
|
||||||
|
if (existingItemIds.find(itemId) == existingItemIds.end())
|
||||||
|
{
|
||||||
|
glz::json_t::object_t newItem;
|
||||||
|
newItem["itemId"] = itemId;
|
||||||
|
newItem["quantity"] = 3;
|
||||||
|
itemsArr.push_back(newItem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!slasher)
|
||||||
|
{
|
||||||
|
appendItems(_camperItems);
|
||||||
|
appendItems(_camperAddons);
|
||||||
|
appendItems(_camperOfferings);
|
||||||
|
appendPerks(_camperPerks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendItems(_slasherAddons);
|
||||||
|
appendItems(_slasherOfferings);
|
||||||
|
appendPerks(_slasherPerks);
|
||||||
|
}
|
||||||
|
appendItems(_globalOfferings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spoofer::modifyCharacterData(glz::generic& js)
|
||||||
|
{
|
||||||
|
if (!js.contains("characterName") || !js["characterName"].is_string())
|
||||||
|
{
|
||||||
|
_log->verbose("attempted to modify invalid char");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = js["characterName"].get_string();
|
||||||
|
|
||||||
|
if (_spoofCharacters)
|
||||||
|
{
|
||||||
|
bool needsLvlSpoofing = false;
|
||||||
|
if (js.contains("isEntitled") && !js["isEntitled"].get_boolean() && js.contains("characterName") &&
|
||||||
|
_unlockedCharacters.contains(js["characterName"].get_string()))
|
||||||
|
{
|
||||||
|
js["isEntitled"] = true;
|
||||||
|
js["purchaseInfo"] = glz::json_t::object_t{{"quantity", 1},
|
||||||
|
{"origin", "PlayerInventory"},
|
||||||
|
{"reason", "Item(s) added via Purchase"},
|
||||||
|
{"lastUpdateAt", static_cast<uint64_t>(std::time(nullptr))},
|
||||||
|
{"objectId", name}};
|
||||||
|
needsLvlSpoofing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsLvlSpoofing)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (js.contains("bloodWebLevel") && js["bloodWebLevel"].is_number() &&
|
||||||
|
js["bloodWebLevel"].get_number() <= 15)
|
||||||
|
if (!js.contains("prestigeLevel") ||
|
||||||
|
(js["prestigeLevel"].is_number() && js["prestigeLevel"].get_number() <= 0))
|
||||||
|
js["bloodWebLevel"] = 16;
|
||||||
|
|
||||||
|
if (js.contains("bloodWebData")) generateBloodweb(js["bloodWebData"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_spoofItems || _spoofPerks) modifyCharacterInventory(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spoofer::generateBloodweb(glz::generic& js)
|
||||||
|
{
|
||||||
|
if (!js.is_object()) js = glz::json_t::object_t{};
|
||||||
|
|
||||||
|
std::vector<std::string> paths;
|
||||||
|
glz::json_t::array_t ringDataArray;
|
||||||
|
|
||||||
|
glz::json_t::object_t rootRing;
|
||||||
|
glz::json_t::array_t rootNodeData;
|
||||||
|
glz::json_t::object_t rootNode;
|
||||||
|
rootNode["nodeId"] = "0";
|
||||||
|
rootNode["state"] = "Collected";
|
||||||
|
rootNodeData.push_back(rootNode);
|
||||||
|
rootRing["nodeData"] = rootNodeData;
|
||||||
|
ringDataArray.push_back(rootRing);
|
||||||
|
|
||||||
|
int nodesPerRing[] = {6, 12, 12};
|
||||||
|
std::vector<std::string> prevRingNodes = {"0"};
|
||||||
|
|
||||||
|
for (int ring = 1; ring <= 3; ++ring)
|
||||||
|
{
|
||||||
|
glz::json_t::array_t nodeDataArray;
|
||||||
|
std::vector<std::string> currentRingNodes;
|
||||||
|
int numNodes = nodesPerRing[ring - 1];
|
||||||
|
|
||||||
|
for (int i = 1; i <= numNodes; ++i)
|
||||||
|
{
|
||||||
|
std::string childId = std::to_string((ring * 100) + i);
|
||||||
|
currentRingNodes.push_back(childId);
|
||||||
|
|
||||||
|
int parentIndex = (i - 1) / (numNodes / static_cast<int>(prevRingNodes.size()));
|
||||||
|
std::string parentId = prevRingNodes[(std::min)(parentIndex, (int)prevRingNodes.size() - 1)];
|
||||||
|
paths.push_back(parentId + "_" + childId);
|
||||||
|
|
||||||
|
std::string item = PLACEHOLDER_ITEM_ID;
|
||||||
|
|
||||||
|
glz::json_t::object_t node;
|
||||||
|
node["nodeId"] = childId;
|
||||||
|
node["state"] = "Collected";
|
||||||
|
node["contentId"] = item;
|
||||||
|
nodeDataArray.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
glz::json_t::object_t ringEntry;
|
||||||
|
ringEntry["nodeData"] = nodeDataArray;
|
||||||
|
ringDataArray.push_back(ringEntry);
|
||||||
|
|
||||||
|
prevRingNodes = std::move(currentRingNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
glz::json_t::array_t pathsArr;
|
||||||
|
for (auto& p : paths)
|
||||||
|
pathsArr.push_back(p);
|
||||||
|
|
||||||
|
js["paths"] = pathsArr;
|
||||||
|
js["ringData"] = ringDataArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
api handlers
|
||||||
|
*/
|
||||||
|
void Spoofer::onServerGetAll(std::string& body)
|
||||||
|
{
|
||||||
|
glz::generic doc{};
|
||||||
|
auto ec = glz::read_json(doc, body);
|
||||||
|
if (ec) return _log->error("JSON parse error for dbd-character-data/get-all");
|
||||||
|
|
||||||
|
if (!doc.is_object() || !doc.get_object().contains("list") || !doc["list"].is_array())
|
||||||
|
return _log->error("Invalid json for dbd-character-data/get-all");
|
||||||
|
|
||||||
|
auto& list = doc["list"].get_array();
|
||||||
|
for (auto& charData : list)
|
||||||
|
modifyCharacterData(charData);
|
||||||
|
|
||||||
|
auto written = glz::write_json(doc);
|
||||||
|
if (written)
|
||||||
|
body = written.value();
|
||||||
|
else
|
||||||
|
_log->error("JSON dump error for dbd-character-data/get-all");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spoofer::onServerInventoryAll(std::string& body)
|
||||||
|
{
|
||||||
|
glz::generic doc{};
|
||||||
|
auto ec = glz::read_json(doc, body);
|
||||||
|
if (ec) return _log->error("JSON parse error for dbd-inventories/all");
|
||||||
|
|
||||||
|
if (!doc.is_object() || !doc.get_object().contains("inventoryItems") || !doc["inventoryItems"].is_array())
|
||||||
|
return _log->error("Invalid json for JSON parse error for dbd-inventories/all");
|
||||||
|
|
||||||
|
auto& itemsArr = doc["inventoryItems"].get_array();
|
||||||
|
std::unordered_set<std::string> existingIds;
|
||||||
|
int64_t now = std::time(nullptr);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, int> spoofMap;
|
||||||
|
|
||||||
|
if (_spoofPerks)
|
||||||
|
{
|
||||||
|
for (const auto& id : _camperPerks)
|
||||||
|
spoofMap[id] = 3;
|
||||||
|
for (const auto& id : _slasherPerks)
|
||||||
|
spoofMap[id] = 3;
|
||||||
|
}
|
||||||
|
if (_spoofItems)
|
||||||
|
{
|
||||||
|
for (const auto& [id, qty] : _camperOfferings)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
for (const auto& [id, qty] : _slasherOfferings)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
for (const auto& [id, qty] : _globalOfferings)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
for (const auto& [id, qty] : _camperItems)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
for (const auto& [id, qty] : _camperAddons)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
for (const auto& [id, qty] : _slasherAddons)
|
||||||
|
spoofMap[id] = qty;
|
||||||
|
}
|
||||||
|
if (_spoofCatalog)
|
||||||
|
{
|
||||||
|
//for (const auto& id : _catalogOutfitIds)
|
||||||
|
//spoofMap[id] = 1;
|
||||||
|
for (const auto& id : _catalogItemIds)
|
||||||
|
spoofMap[id] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
item updates
|
||||||
|
*/
|
||||||
|
for (auto& item : itemsArr)
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
if (item.is_object() && item.get_object().contains("objectId") && item["objectId"].is_string())
|
||||||
|
id = item["objectId"].get<std::string>();
|
||||||
|
|
||||||
|
if (id.empty()) continue;
|
||||||
|
existingIds.insert(id);
|
||||||
|
|
||||||
|
auto it = spoofMap.find(id);
|
||||||
|
if (it != spoofMap.end()) item["quantity"] = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
item inserts
|
||||||
|
*/
|
||||||
|
for (const auto& [id, qty] : spoofMap)
|
||||||
|
{
|
||||||
|
if (!existingIds.contains(id))
|
||||||
|
{
|
||||||
|
glz::json_t::object_t newItem;
|
||||||
|
newItem["objectId"] = id;
|
||||||
|
newItem["quantity"] = qty;
|
||||||
|
newItem["lastUpdateAt"] = now;
|
||||||
|
itemsArr.push_back(newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto written = glz::write_json(doc);
|
||||||
|
if (written)
|
||||||
|
body = written.value();
|
||||||
|
else
|
||||||
|
_log->error("JSON dump error for dbd-inventories/all");
|
||||||
|
|
||||||
|
_log->verbose("Inventory spoofed");
|
||||||
|
}
|
||||||
|
|
||||||
void Spoofer::onServerMessageList(std::string& body)
|
void Spoofer::onServerMessageList(std::string& body)
|
||||||
{
|
{
|
||||||
glz::generic doc;
|
glz::generic doc;
|
||||||
@@ -302,10 +602,101 @@ void Spoofer::onServerMessageList(std::string& body)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
_log->verbose("Spoofed message list");
|
_log->verbose("Spoofed message list");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spoofer::onServerBloodweb(std::string& body, std::string& respHeaders)
|
||||||
|
{
|
||||||
|
glz::generic doc;
|
||||||
|
auto ec = glz::read_json(doc, body);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
_log->error("JSON parse error for onServerBloodweb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
false char response
|
||||||
|
*/
|
||||||
|
if (body.find("NotAllowedException") != std::string::npos && body.find("not owned") != std::string::npos)
|
||||||
|
{
|
||||||
|
glz::generic mock = glz::generic::object_t{};
|
||||||
|
mock["bloodWebLevelChanged"] = false;
|
||||||
|
mock["updatedWallets"] = glz::generic::array_t{};
|
||||||
|
mock["bloodWebLevel"] = 16;
|
||||||
|
mock["prestigeLevel"] = 0;
|
||||||
|
mock["bloodWebData"] = glz::generic::object_t{};
|
||||||
|
mock["characterItems"] = glz::generic::array_t{};
|
||||||
|
mock["characterName"] = this->_lastBwCharacter;
|
||||||
|
mock["isEntitled"] = true;
|
||||||
|
|
||||||
|
glz::generic::object_t purchaseInfo;
|
||||||
|
purchaseInfo["quantity"] = 1;
|
||||||
|
purchaseInfo["origin"] = "PlayerInventory";
|
||||||
|
purchaseInfo["reason"] = "Item(s) added via Purchase";
|
||||||
|
purchaseInfo["lastUpdateAt"] = static_cast<uint64_t>(std::time(nullptr));
|
||||||
|
purchaseInfo["objectId"] = this->_lastBwCharacter;
|
||||||
|
|
||||||
|
mock["purchaseInfo"] = purchaseInfo;
|
||||||
|
|
||||||
|
if (_spoofCharacters) generateBloodweb(mock["bloodWebData"]);
|
||||||
|
|
||||||
|
if (_spoofItems || _spoofPerks) modifyCharacterInventory(mock);
|
||||||
|
|
||||||
|
std::string new_body;
|
||||||
|
ec = glz::write_json(mock, new_body);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
_log->error("JSON write error for onServerBloodweb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
body = new_body;
|
||||||
|
|
||||||
|
std::regex statusRegex(R"(HTTP\/\d\.\d\s+403)");
|
||||||
|
respHeaders = std::regex_replace(respHeaders, statusRegex, "HTTP/1.1 200");
|
||||||
|
|
||||||
|
_log->verbose("Spoofed bloodweb request for unowned character.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bloodweb fixup for already owned perks
|
||||||
|
*/
|
||||||
|
if (_spoofPerks)
|
||||||
|
{
|
||||||
|
if (doc.contains("bloodWebData") && doc["bloodWebData"].is_object())
|
||||||
|
{
|
||||||
|
auto& bloodWebData = doc["bloodWebData"];
|
||||||
|
|
||||||
|
if (!bloodWebData.contains("paths") || !bloodWebData.contains("ringData")) return;
|
||||||
|
|
||||||
|
for (auto& ring : bloodWebData["ringData"].get_array())
|
||||||
|
{
|
||||||
|
if (!ring.contains("nodeData") || !ring["nodeData"].is_array()) continue;
|
||||||
|
|
||||||
|
for (auto& node : ring["nodeData"].get_array())
|
||||||
|
{
|
||||||
|
if (!node.contains("contentId") || !node["contentId"].is_string()) continue;
|
||||||
|
|
||||||
|
std::string contentId = node["contentId"].get_string();
|
||||||
|
if (_camperPerks.contains(contentId) || _slasherPerks.contains(contentId))
|
||||||
|
node["contentId"] = PLACEHOLDER_ITEM_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_log->verbose("Fixed bloodweb request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyCharacterData(doc);
|
||||||
|
|
||||||
|
auto written = glz::write_json(doc);
|
||||||
|
if (written)
|
||||||
|
body = written.value();
|
||||||
|
else
|
||||||
|
_log->error("JSON write error for onServerBloodweb");
|
||||||
|
|
||||||
|
_log->verbose("Spoofed bloodweb items for owned character");
|
||||||
|
}
|
||||||
|
|
||||||
void Spoofer::onServerUpdateEntitlements(const std::string& url, std::string& body)
|
void Spoofer::onServerUpdateEntitlements(const std::string& url, std::string& body)
|
||||||
{
|
{
|
||||||
if (!_spoofDLCs) return;
|
if (!_spoofDLCs) return;
|
||||||
@@ -346,10 +737,22 @@ void Spoofer::onServerUpdateEntitlements(const std::string& url, std::string& bo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
_log->verbose("Spoofed entitlements (response)");
|
||||||
_log->verbose("Spoofed entitlements (client)");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spoofer::onClientBloodweb(std::string& body)
|
||||||
|
{
|
||||||
|
glz::generic doc;
|
||||||
|
auto ec = glz::read_json(doc, body);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
_log->error("JSON parse error for onClientBloodweb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc.contains("characterName")) _lastBwCharacter = doc["characterName"].get_string();
|
||||||
|
}
|
||||||
|
|
||||||
void Spoofer::onClientUpdateEntitlements(const std::string& url, std::string& body)
|
void Spoofer::onClientUpdateEntitlements(const std::string& url, std::string& body)
|
||||||
{
|
{
|
||||||
if (!_spoofDLCs) return;
|
if (!_spoofDLCs) return;
|
||||||
@@ -390,9 +793,7 @@ void Spoofer::onClientUpdateEntitlements(const std::string& url, std::string& bo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
_log->verbose("Spoofed entitlements (client)");
|
_log->verbose("Spoofed entitlements (client)");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -406,11 +807,19 @@ void Spoofer::serverResponseHandler(const std::string& url, std::string& body, s
|
|||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
|
||||||
if (url.find("/api/v1/messages/listV2") != std::string::npos) return onServerMessageList(body);
|
if (url.find("/api/v1/messages/listV2") != std::string::npos) return onServerMessageList(body);
|
||||||
|
if (url.find("/api/v1/dbd-inventories/all") != std::string::npos) return onServerInventoryAll(body);
|
||||||
|
if (url.find("/api/v1/dbd-character-data/get-all") != std::string::npos) return onServerGetAll(body);
|
||||||
if (url.find("/api/v1/owned-products/get-update-entitlements") != std::string::npos)
|
if (url.find("/api/v1/owned-products/get-update-entitlements") != std::string::npos)
|
||||||
return onServerUpdateEntitlements(url, body);
|
return onServerUpdateEntitlements(url, body);
|
||||||
|
|
||||||
|
if (url.find("/api/v1/dbd-character-data/bloodweb") != std::string::npos ||
|
||||||
|
url.find("/api/v1/dbd-character-data/bloodweb/v2") != std::string::npos ||
|
||||||
|
url.find("/api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos)
|
||||||
|
return onServerBloodweb(body, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spoofer::clientRequestHandler(const std::string& url, std::string& body, std::string& /*headers*/, bool /*wasBlocked*/)
|
void Spoofer::clientRequestHandler(const std::string& url, std::string& body, std::string& /*headers*/,
|
||||||
|
bool /*wasBlocked*/)
|
||||||
{
|
{
|
||||||
if (url.find("bhvrdbd.com") == std::string::npos) return;
|
if (url.find("bhvrdbd.com") == std::string::npos) return;
|
||||||
|
|
||||||
@@ -418,4 +827,9 @@ void Spoofer::clientRequestHandler(const std::string& url, std::string& body, st
|
|||||||
|
|
||||||
if (url.find("/api/v1/owned-products/get-update-entitlements") != std::string::npos)
|
if (url.find("/api/v1/owned-products/get-update-entitlements") != std::string::npos)
|
||||||
return onClientUpdateEntitlements(url, body);
|
return onClientUpdateEntitlements(url, body);
|
||||||
|
|
||||||
|
if (url.find("/api/v1/dbd-character-data/bloodweb") != std::string::npos ||
|
||||||
|
url.find("/api/v1/dbd-character-data/bloodweb/v2") != std::string::npos ||
|
||||||
|
url.find("/api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos)
|
||||||
|
return onClientBloodweb(body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,13 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <glaze/glaze.hpp>
|
||||||
|
|
||||||
#define WS_ADDR "0.0.0.0"
|
#define WS_ADDR "0.0.0.0"
|
||||||
#define WS_PORT 4444
|
#define WS_PORT 4444
|
||||||
|
|
||||||
|
#define PLACEHOLDER_ITEM_ID "Anniversary2025Offering"
|
||||||
|
|
||||||
class TinyMITMProxy;
|
class TinyMITMProxy;
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
@@ -97,6 +101,27 @@ class Spoofer
|
|||||||
|
|
||||||
void wsMessageCallback(std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket& webSocket,
|
void wsMessageCallback(std::shared_ptr<ix::ConnectionState> connectionState, ix::WebSocket& webSocket,
|
||||||
const std::unique_ptr<ix::WebSocketMessage>& msg);
|
const std::unique_ptr<ix::WebSocketMessage>& msg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
helpers
|
||||||
|
*/
|
||||||
|
void modifyCharacterInventory(glz::generic& js);
|
||||||
|
void modifyCharacterData(glz::generic& js);
|
||||||
|
void generateBloodweb(glz::generic& js);
|
||||||
|
|
||||||
|
/*
|
||||||
|
api handlers
|
||||||
|
*/
|
||||||
|
void onServerGetAll(std::string& body);
|
||||||
|
void onServerInventoryAll(std::string& body);
|
||||||
|
void onServerMessageList(std::string& body);
|
||||||
|
void onServerBloodweb(std::string& body, std::string& respHeaders);
|
||||||
|
void onServerUpdateEntitlements(const std::string& url, std::string& body);
|
||||||
|
|
||||||
|
void onClientGetAll(std::string& body);
|
||||||
|
void onClientBloodweb(std::string& body);
|
||||||
|
void onClientUpdateEntitlements(const std::string& url, std::string& body);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
proxy handlers
|
proxy handlers
|
||||||
*/
|
*/
|
||||||
@@ -111,6 +136,7 @@ class Spoofer
|
|||||||
bool _spoofPerks = false;
|
bool _spoofPerks = false;
|
||||||
bool _spoofCatalog = false;
|
bool _spoofCatalog = false;
|
||||||
bool _spoofDLCs = false;
|
bool _spoofDLCs = false;
|
||||||
|
bool _spoofCharacters = false;
|
||||||
|
|
||||||
std::unordered_map<std::string, int> _camperItems;
|
std::unordered_map<std::string, int> _camperItems;
|
||||||
std::unordered_map<std::string, int> _camperAddons;
|
std::unordered_map<std::string, int> _camperAddons;
|
||||||
@@ -136,4 +162,5 @@ class Spoofer
|
|||||||
ix::WebSocketServer* _wsServer = nullptr;
|
ix::WebSocketServer* _wsServer = nullptr;
|
||||||
seallib::Logger* _log = nullptr;
|
seallib::Logger* _log = nullptr;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
|
std::string _lastBwCharacter;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user