Squashed commit of the following:
commit f44d146e4ac906ff898e8968c6857fd2280f6d20 Author: project-bo4 <127137346+project-bo4@users.noreply.github.com> Date: Thu May 11 13:39:29 2023 -0700 remove lpc package from repository commit 29fb0f63e50de468ab0b9db35f7e8fdadf58afc3 Author: project-bo4 <themanwithantidote@gmail.com> Date: Thu May 11 13:06:13 2023 -0700 generic improvements + added identity configuration + objectstore improvements + added battlenet 'US' servers to blocklist + some other minor improvements commit 5d5e31099ebcce5a637b9a02d4936a97fb0802a7 Author: project-bo4 <themanwithantidote@gmail.com> Date: Sat Mar 25 16:32:52 2023 -0700 lpc improvements + fix lpc issue with foreign languages(non-english) not being considered in listing + check lpc files pre-start and warn user if missing any of core items commit 2de1a54b6f4cc5c44dc906871021cfbc85057ca9 Author: project-bo4 <themanwithantidote@gmail.com> Date: Thu Mar 23 12:45:56 2023 -0700 demonware improvements + handle object store uploadUserObject + silence bdUNK125 commit 710dcc3ec6178071d67c27e5bf6705f08cabe7e2 Author: project-bo4 <themanwithantidote@gmail.com> Date: Mon Mar 20 13:43:56 2023 -0700 forgot to update names commit 217682dfb07b35f7a09399fb2698924bb7fe8b77 Author: project-bo4 <themanwithantidote@gmail.com> Date: Mon Mar 20 11:09:18 2023 -0700 upload lpc and update readme commit 83f812b33b90791a8d13b9468f27da51e0a4f2b9 Author: project-bo4 <themanwithantidote@gmail.com> Date: Mon Mar 20 10:53:43 2023 -0700 demonware emulator + demonware emulator + platform name and id + xxhash and picoproto - remove g_runframe hook -disable discovery(save time) + improvements to utils + add new resources
This commit is contained in:
parent
7e2d784c22
commit
354d022967
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -22,3 +22,9 @@
|
||||
[submodule "deps/winreg"]
|
||||
path = deps/winreg
|
||||
url = https://github.com/GiovanniDicanio/WinReg.git
|
||||
[submodule "deps/picoproto"]
|
||||
path = deps/picoproto
|
||||
url = https://github.com/petewarden/picoproto.git
|
||||
[submodule "deps/xxhash"]
|
||||
path = deps/xxhash
|
||||
url = https://github.com/stbrumme/xxhash.git
|
||||
|
20
README.md
20
README.md
@ -1,25 +1,25 @@
|
||||
"**They tried to bury us, they didn't know we were seeds**"
|
||||
|
||||
![code](https://raw.githubusercontent.com/project-bo4/shield-development/master/assets/readme_header.jpg)
|
||||
|
||||
## SHIELD
|
||||
A very experimental modification platform for Call of Duty®: Black Ops 4 run by community, aiming at improving both functionality and performance of original game.
|
||||
|
||||
This repository is designated as development period repo. final product will be set in a separate repo and is not guaranteed to carry over everything featured here.
|
||||
|
||||
## DEMONWARE
|
||||
As of May11, 2023 we merged 'demonware' branch into 'master'. it includes a built-in demonware server emulator which allows player to start game without connection to official online servers.
|
||||
|
||||
|
||||
## LIMITATIONS
|
||||
This repo only contains client-side detours and is not included with server code. As of right now, server code is planned to be private to let us maintain slight control over it and prevent and ban violatars those who cant even obey basic rules and tend to ruin experience of other users and take fun away from them.
|
||||
## INSTRUCTION
|
||||
-- you should have publisher files required for play online under LPC folder of your game installation. if its not the case then start original game through battlenet launcher once to get those downloaded.
|
||||
|
||||
If you looking forward experimenting and in-dependent development from project-bo4 servers check out [demonware](https://github.com/project-bo4/shield-development/tree/demonware) branch including built-in bo4 dw server emulator.
|
||||
1- clone repository with its sub-modules and use generate.bat to make visual studio solution then compile project and copy ``d3d11.dll`` into your bo4 folder.
|
||||
|
||||
2- start BlackOps4.exe
|
||||
|
||||
|
||||
|
||||
## NOTES
|
||||
- Base SDK(well kinda...) used by this project is developed by [Maurice Heumann](https://github.com/momo5502); Thanks to the guy 🫡
|
||||
|
||||
- To compile: clone repository using gitbash/powershell terminal; start generate.bat and it will grab all of required sub-modules and make visual studio solution which can be used to compile the client.
|
||||
- Base SDK(well kinda...) used by this project is developed by [Maurice Heumann](https://github.com/momo5502); Thanks to the guy.
|
||||
|
||||
- There are some 3rd-party project/tools that have influenced and helped the project in particular ways; If you belive there is something originated from you and want to be credited please contact any of our social media accounts.
|
||||
|
||||
- This Project is created purely for educational purposes. its free and open-sourced under gnu license. developers are not responsible or liable for misuse of this product.
|
||||
- This Project is created purely for educational purposes. its free and open-sourced under gnu license. developers are not responsible or liable for misuse of this product.
|
1
deps/picoproto
vendored
Submodule
1
deps/picoproto
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 116b45be9c1b1ab7b44b620cf00209d226d3e776
|
31
deps/premake/picoproto.lua
vendored
Normal file
31
deps/premake/picoproto.lua
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
picoproto = {
|
||||
source = path.join(dependencies.basePath, "picoproto"),
|
||||
}
|
||||
|
||||
function picoproto.import()
|
||||
links { "picoproto" }
|
||||
picoproto.includes()
|
||||
end
|
||||
|
||||
function picoproto.includes()
|
||||
includedirs {
|
||||
picoproto.source
|
||||
}
|
||||
end
|
||||
|
||||
function picoproto.project()
|
||||
project "picoproto"
|
||||
language "C"
|
||||
|
||||
picoproto.includes()
|
||||
|
||||
files {
|
||||
path.join(picoproto.source, "picoproto.cc"),
|
||||
path.join(picoproto.source, "picoproto.h"),
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, picoproto)
|
19
deps/premake/xxhash.lua
vendored
Normal file
19
deps/premake/xxhash.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
xxhash = {
|
||||
source = path.join(dependencies.basePath, "xxhash"),
|
||||
}
|
||||
|
||||
function xxhash.import()
|
||||
xxhash.includes()
|
||||
end
|
||||
|
||||
function xxhash.includes()
|
||||
includedirs {
|
||||
xxhash.source
|
||||
}
|
||||
end
|
||||
|
||||
function xxhash.project()
|
||||
disablewarnings { "4244" }
|
||||
end
|
||||
|
||||
table.insert(dependencies, xxhash)
|
1
deps/xxhash
vendored
Submodule
1
deps/xxhash
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c2866db364b6ea3a11933e62235ddc166ba18565
|
@ -1,30 +1,137 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/thread.hpp>
|
||||
|
||||
#include "demonware/servers/lobby_server.hpp"
|
||||
#include "demonware/servers/auth3_server.hpp"
|
||||
#include "demonware/servers/stun_server.hpp"
|
||||
#include "demonware/servers/umbrella_server.hpp"
|
||||
#include "demonware/server_registry.hpp"
|
||||
|
||||
#define TCP_BLOCKING true
|
||||
#define UDP_BLOCKING false
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
const char* blocked_hosts[] =
|
||||
const char* blocked_hosts[] =
|
||||
{
|
||||
"us.cdn.blizzard.com",
|
||||
"us.actual.battle.net",
|
||||
"eu.cdn.blizzard.com",
|
||||
"eu.actual.battle.net",
|
||||
"level3.blizzard.com",
|
||||
"blzddist1-a.akamaihd.net",
|
||||
"level3.ssl.blizzard.com",
|
||||
"eu.actual.battle.net"
|
||||
"level3.ssl.blizzard.com"
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
std::atomic_bool exit_server{ false };
|
||||
std::thread server_thread{};
|
||||
utils::concurrency::container<std::unordered_map<SOCKET, bool>> blocking_sockets{};
|
||||
utils::concurrency::container<std::unordered_map<SOCKET, tcp_server*>> socket_map{};
|
||||
server_registry<tcp_server> tcp_servers{};
|
||||
server_registry<udp_server> udp_servers{};
|
||||
std::unordered_map<void*, void*> original_imports{};
|
||||
|
||||
namespace network
|
||||
tcp_server* find_server(const SOCKET socket)
|
||||
{
|
||||
return socket_map.access<tcp_server*>([&](const std::unordered_map<SOCKET, tcp_server*>& map) -> tcp_server*
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return entry->second;
|
||||
});
|
||||
}
|
||||
|
||||
bool socket_link(const SOCKET socket, const uint32_t address)
|
||||
{
|
||||
auto* server = tcp_servers.find(address);
|
||||
if (!server)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& map)
|
||||
{
|
||||
map[socket] = server;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void socket_unlink(const SOCKET socket)
|
||||
{
|
||||
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& map)
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry != map.end())
|
||||
{
|
||||
map.erase(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool is_socket_blocking(const SOCKET socket, const bool def)
|
||||
{
|
||||
return blocking_sockets.access<bool>([&](std::unordered_map<SOCKET, bool>& map)
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
return entry->second;
|
||||
});
|
||||
}
|
||||
|
||||
void remove_blocking_socket(const SOCKET socket)
|
||||
{
|
||||
blocking_sockets.access([&](std::unordered_map<SOCKET, bool>& map)
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry != map.end())
|
||||
{
|
||||
map.erase(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void add_blocking_socket(const SOCKET socket, const bool block)
|
||||
{
|
||||
blocking_sockets.access([&](std::unordered_map<SOCKET, bool>& map)
|
||||
{
|
||||
map[socket] = block;
|
||||
});
|
||||
}
|
||||
|
||||
void server_main()
|
||||
{
|
||||
exit_server = false;
|
||||
|
||||
while (!exit_server)
|
||||
{
|
||||
tcp_servers.frame();
|
||||
udp_servers.frame();
|
||||
std::this_thread::sleep_for(50ms);
|
||||
}
|
||||
}
|
||||
|
||||
namespace io
|
||||
{
|
||||
int getaddrinfo_stub(const char* name, const char* service,
|
||||
const addrinfo* hints, addrinfo** res)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[ NETWORK ]: [getaddrinfo]: \"%s\" \"%s\"", name, service);
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[ network ]: [getaddrinfo]: \"%s\" \"%s\"", name, service);
|
||||
#endif
|
||||
|
||||
for (auto i = 0; i < ARRAYSIZE(blocked_hosts); ++i)
|
||||
@ -35,22 +142,299 @@ namespace demonware
|
||||
}
|
||||
}
|
||||
|
||||
return WSAHOST_NOT_FOUND;
|
||||
/* TODO: RE-ROUTE DW HOSTS TO CUSTOM DW SERVER */
|
||||
base_server* server = tcp_servers.find(name);
|
||||
if (!server)
|
||||
{
|
||||
server = udp_servers.find(name);
|
||||
}
|
||||
|
||||
return getaddrinfo(name, service, hints, res);
|
||||
if (!server)
|
||||
{
|
||||
return getaddrinfo(name, service, hints, res);
|
||||
}
|
||||
|
||||
const auto address = utils::memory::get_allocator()->allocate<sockaddr>();
|
||||
const auto ai = utils::memory::get_allocator()->allocate<addrinfo>();
|
||||
|
||||
auto in_addr = reinterpret_cast<sockaddr_in*>(address);
|
||||
in_addr->sin_addr.s_addr = server->get_address();
|
||||
in_addr->sin_family = AF_INET;
|
||||
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
ai->ai_addr = address;
|
||||
ai->ai_addrlen = sizeof(sockaddr);
|
||||
ai->ai_next = nullptr;
|
||||
ai->ai_flags = 0;
|
||||
ai->ai_protocol = 0;
|
||||
ai->ai_canonname = const_cast<char*>(name);
|
||||
|
||||
*res = ai;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void freeaddrinfo_stub(addrinfo* ai)
|
||||
{
|
||||
if (!utils::memory::get_allocator()->find(ai))
|
||||
{
|
||||
return freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
utils::memory::get_allocator()->free(ai->ai_addr);
|
||||
utils::memory::get_allocator()->free(ai);
|
||||
}
|
||||
|
||||
int getpeername_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
auto* server = find_server(s);
|
||||
|
||||
if (server)
|
||||
{
|
||||
auto in_addr = reinterpret_cast<sockaddr_in*>(addr);
|
||||
in_addr->sin_addr.s_addr = server->get_address();
|
||||
in_addr->sin_family = AF_INET;
|
||||
*addrlen = sizeof(sockaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getpeername(s, addr, addrlen);
|
||||
}
|
||||
|
||||
int getsockname_stub(const SOCKET s, sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
auto* server = find_server(s);
|
||||
|
||||
if (server)
|
||||
{
|
||||
auto in_addr = reinterpret_cast<sockaddr_in*>(addr);
|
||||
in_addr->sin_addr.s_addr = server->get_address();
|
||||
in_addr->sin_family = AF_INET;
|
||||
*addrlen = sizeof(sockaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getsockname(s, addr, addrlen);
|
||||
}
|
||||
|
||||
hostent* gethostbyname_stub(const char* name)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[ NETWORK ]: [gethostbyname]: \"%s\"", name);
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[ network ]: [gethostbyname]: \"%s\"", name);
|
||||
#endif
|
||||
|
||||
base_server* server = tcp_servers.find(name);
|
||||
if (!server)
|
||||
{
|
||||
server = udp_servers.find(name);
|
||||
}
|
||||
|
||||
if (!server)
|
||||
{
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
return gethostbyname(name);
|
||||
return gethostbyname(name);
|
||||
#pragma warning(pop)
|
||||
}
|
||||
|
||||
static thread_local in_addr address{};
|
||||
address.s_addr = server->get_address();
|
||||
|
||||
static thread_local in_addr* addr_list[2]{};
|
||||
addr_list[0] = &address;
|
||||
addr_list[1] = nullptr;
|
||||
|
||||
static thread_local hostent host{};
|
||||
host.h_name = const_cast<char*>(name);
|
||||
host.h_aliases = nullptr;
|
||||
host.h_addrtype = AF_INET;
|
||||
host.h_length = sizeof(in_addr);
|
||||
host.h_addr_list = reinterpret_cast<char**>(addr_list);
|
||||
|
||||
return &host;
|
||||
}
|
||||
|
||||
int connect_stub(const SOCKET s, const struct sockaddr* addr, const int len)
|
||||
{
|
||||
if (len == sizeof(sockaddr_in))
|
||||
{
|
||||
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(addr);
|
||||
if (socket_link(s, in_addr->sin_addr.s_addr)) return 0;
|
||||
}
|
||||
|
||||
return connect(s, addr, len);
|
||||
}
|
||||
|
||||
int closesocket_stub(const SOCKET s)
|
||||
{
|
||||
remove_blocking_socket(s);
|
||||
socket_unlink(s);
|
||||
|
||||
return closesocket(s);
|
||||
}
|
||||
|
||||
int send_stub(const SOCKET s, const char* buf, const int len, const int flags)
|
||||
{
|
||||
auto* server = find_server(s);
|
||||
|
||||
if (server)
|
||||
{
|
||||
server->handle_input(buf, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
return send(s, buf, len, flags);
|
||||
}
|
||||
|
||||
int recv_stub(const SOCKET s, char* buf, const int len, const int flags)
|
||||
{
|
||||
auto* server = find_server(s);
|
||||
|
||||
if (server)
|
||||
{
|
||||
if (server->pending_data())
|
||||
{
|
||||
return static_cast<int>(server->handle_output(buf, len));
|
||||
}
|
||||
else
|
||||
{
|
||||
WSASetLastError(WSAEWOULDBLOCK);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return recv(s, buf, len, flags);
|
||||
}
|
||||
|
||||
int sendto_stub(const SOCKET s, const char* buf, const int len, const int flags, const sockaddr* to,
|
||||
const int tolen)
|
||||
{
|
||||
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(to);
|
||||
auto* server = udp_servers.find(in_addr->sin_addr.s_addr);
|
||||
|
||||
if (server)
|
||||
{
|
||||
server->handle_input(buf, len, { s, to, tolen });
|
||||
return len;
|
||||
}
|
||||
|
||||
return sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
int recvfrom_stub(const SOCKET s, char* buf, const int len, const int flags, struct sockaddr* from,
|
||||
int* fromlen)
|
||||
{
|
||||
// Not supported yet
|
||||
if (is_socket_blocking(s, UDP_BLOCKING))
|
||||
{
|
||||
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||
}
|
||||
|
||||
size_t result = 0;
|
||||
udp_servers.for_each([&](udp_server& server)
|
||||
{
|
||||
if (server.pending_data(s))
|
||||
{
|
||||
result = server.handle_output(
|
||||
s, buf, static_cast<size_t>(len), from, fromlen);
|
||||
}
|
||||
});
|
||||
|
||||
if (result)
|
||||
{
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||
}
|
||||
|
||||
int select_stub(const int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds,
|
||||
struct timeval* timeout)
|
||||
{
|
||||
if (exit_server)
|
||||
{
|
||||
return select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
|
||||
auto result = 0;
|
||||
std::vector<SOCKET> read_sockets;
|
||||
std::vector<SOCKET> write_sockets;
|
||||
|
||||
socket_map.access([&](std::unordered_map<SOCKET, tcp_server*>& sockets)
|
||||
{
|
||||
for (auto& s : sockets)
|
||||
{
|
||||
if (readfds)
|
||||
{
|
||||
if (FD_ISSET(s.first, readfds))
|
||||
{
|
||||
if (s.second->pending_data())
|
||||
{
|
||||
read_sockets.push_back(s.first);
|
||||
FD_CLR(s.first, readfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writefds)
|
||||
{
|
||||
if (FD_ISSET(s.first, writefds))
|
||||
{
|
||||
write_sockets.push_back(s.first);
|
||||
FD_CLR(s.first, writefds);
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptfds)
|
||||
{
|
||||
if (FD_ISSET(s.first, exceptfds))
|
||||
{
|
||||
FD_CLR(s.first, exceptfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if ((!readfds || readfds->fd_count == 0) && (!writefds || writefds->fd_count == 0))
|
||||
{
|
||||
timeout->tv_sec = 0;
|
||||
timeout->tv_usec = 0;
|
||||
}
|
||||
|
||||
result = select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
if (result < 0) result = 0;
|
||||
|
||||
for (const auto& socket : read_sockets)
|
||||
{
|
||||
if (readfds)
|
||||
{
|
||||
FD_SET(socket, readfds);
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& socket : write_sockets)
|
||||
{
|
||||
if (writefds)
|
||||
{
|
||||
FD_SET(socket, writefds);
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ioctlsocket_stub(const SOCKET s, const long cmd, u_long* argp)
|
||||
{
|
||||
if (static_cast<unsigned long>(cmd) == (FIONBIO))
|
||||
{
|
||||
add_blocking_socket(s, *argp == 0);
|
||||
}
|
||||
|
||||
return ioctlsocket(s, cmd, argp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +453,15 @@ namespace demonware
|
||||
|
||||
original_imports[result->first] = result->second;
|
||||
}
|
||||
|
||||
void check_lpc_files()
|
||||
{
|
||||
if (!utils::io::file_exists("LPC/.manifest") || !utils::io::file_exists("LPC/core_ffotd_tu23_639_cf92ecf4a75d3f79.ff") || !utils::io::file_exists("LPC/core_playlists_tu23_639_cf92ecf4a75d3f79.ff"))
|
||||
{
|
||||
MessageBoxA(nullptr, "some required LPC files seems to be missing. You need to get and place them manually since this emulator doesnt host and provide those files; read instructions in github documentation for more info.",
|
||||
"LPC Files Missing", MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -76,17 +469,39 @@ namespace demonware
|
||||
public:
|
||||
component()
|
||||
{
|
||||
/* PLACE_HOLDER */
|
||||
udp_servers.create<stun_server>("ops4-stun.us.demonware.net");
|
||||
udp_servers.create<stun_server>("ops4-stun.eu.demonware.net");
|
||||
udp_servers.create<stun_server>("ops4-stun.jp.demonware.net");
|
||||
udp_servers.create<stun_server>("ops4-stun.au.demonware.net");
|
||||
|
||||
tcp_servers.create<auth3_server>("ops4-pc-auth3.prod.demonware.net");
|
||||
tcp_servers.create<lobby_server>("ops4-pc-lobby.prod.demonware.net");
|
||||
tcp_servers.create<umbrella_server>("prod.umbrella.demonware.net");
|
||||
}
|
||||
|
||||
void pre_start() override
|
||||
{
|
||||
register_hook("gethostbyname", network::gethostbyname_stub);
|
||||
register_hook("getaddrinfo", network::getaddrinfo_stub);
|
||||
register_hook("send", io::send_stub);
|
||||
register_hook("recv", io::recv_stub);
|
||||
register_hook("sendto", io::sendto_stub);
|
||||
register_hook("recvfrom", io::recvfrom_stub);
|
||||
register_hook("connect", io::connect_stub);
|
||||
register_hook("select", io::select_stub);
|
||||
register_hook("closesocket", io::closesocket_stub);
|
||||
register_hook("ioctlsocket", io::ioctlsocket_stub);
|
||||
register_hook("gethostbyname", io::gethostbyname_stub);
|
||||
register_hook("getaddrinfo", io::getaddrinfo_stub);
|
||||
register_hook("freeaddrinfo", io::freeaddrinfo_stub);
|
||||
register_hook("getpeername", io::getpeername_stub);
|
||||
register_hook("getsockname", io::getsockname_stub);
|
||||
|
||||
check_lpc_files();
|
||||
}
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
server_thread = utils::thread::create_named_thread("Demonware", server_main);
|
||||
|
||||
utils::hook::set<uint8_t>(0x144508469_g, 0x0); // CURLOPT_SSL_VERIFYPEER
|
||||
utils::hook::set<uint8_t>(0x144508455_g, 0xAF); // CURLOPT_SSL_VERIFYHOST
|
||||
utils::hook::set<uint8_t>(0x144B28D98_g, 0x0); // HTTPS -> HTTP
|
||||
@ -94,19 +509,16 @@ namespace demonware
|
||||
utils::hook::copy_string(0x144A27C70_g, "http://prod.umbrella.demonware.net");
|
||||
utils::hook::copy_string(0x144A2BAA0_g, "http://prod.uno.demonware.net/v1.0");
|
||||
utils::hook::copy_string(0x144A29CB0_g, "http://%s:%d/auth/");
|
||||
|
||||
|
||||
/*************************************************************************************************************
|
||||
** TODO : in order to record match, while playing (as host?) game live-streams netcode to the content server
|
||||
** continuously troughout the play time. planning to patch it so it streams in memory before uploading
|
||||
** full demo at end of match to improve network performance
|
||||
**
|
||||
**
|
||||
*************************************************************************************************************/
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
exit_server = true;
|
||||
if (server_thread.joinable())
|
||||
{
|
||||
server_thread.join();
|
||||
}
|
||||
|
||||
for (const auto& import : original_imports)
|
||||
{
|
||||
utils::hook::set(import.first, import.second);
|
||||
|
@ -72,7 +72,7 @@ namespace exception
|
||||
utils::thread::suspend_other_threads();
|
||||
show_mouse_cursor();
|
||||
|
||||
MessageBoxA(nullptr, error_str.data(), "Project-bo4 ERROR", MB_ICONERROR);
|
||||
MessageBoxA(nullptr, error_str.data(), "Project-BO4 ERROR", MB_ICONERROR);
|
||||
TerminateProcess(GetCurrentProcess(), exception_data.code);
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ namespace exception
|
||||
++recovery_data.recovery_counts;
|
||||
|
||||
game::Com_Error(game::ERR_DROP, "Fatal error (0x%08X) at 0x%p (0x%p).\nA minidump has been written.\n\n"
|
||||
"BOIII has tried to recover your game, but it might not run stable anymore.\n\n"
|
||||
"Project-BO4 has tried to recover your game, but it might not run stable anymore.\n\n"
|
||||
"Make sure to update your graphics card drivers and install operating system updates!\n"
|
||||
"Closing or restarting Steam might also help.",
|
||||
exception_data.code, exception_data.address,
|
||||
@ -129,7 +129,7 @@ namespace exception
|
||||
info.append("\r\n");
|
||||
};
|
||||
|
||||
line("Project-bo4 Crash Dump");
|
||||
line("Project-BO4 Crash Dump");
|
||||
line("");
|
||||
line(game::version_string);
|
||||
//line("Version: "s + VERSION);
|
||||
|
31
source/proxy-dll/component/experimental.cpp
Normal file
31
source/proxy-dll/component/experimental.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <std_include.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour liveinventory_getitemquantity_hook;
|
||||
int liveinventory_getitemquantity_stub(int controller_index, const int item_id)
|
||||
{
|
||||
return 1; // TODO: Higher quanity for zombie consumable loot
|
||||
|
||||
return liveinventory_getitemquantity_hook.invoke<int>(controller_index, item_id);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
liveinventory_getitemquantity_hook.create(0x1437F6ED0_g, liveinventory_getitemquantity_stub);
|
||||
|
||||
utils::hook::set(0x142DD0E10_g, 0xC301B0); // Live_Qos_Finished
|
||||
utils::hook::set(0x1438C2C70_g, 0xC301B0); // Live_Contracts? related to bdUNK125
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(experimental::component)
|
@ -8,23 +8,20 @@
|
||||
|
||||
namespace logger
|
||||
{
|
||||
std::string get_type_str(const int type)
|
||||
const char* LogTypeNames[] =
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
return "INFO";
|
||||
case 2:
|
||||
return "WARN";
|
||||
case 3:
|
||||
return "ERROR";
|
||||
default:
|
||||
return "DEBUG";
|
||||
}
|
||||
}
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"WARN",
|
||||
"ERROR"
|
||||
};
|
||||
|
||||
void write(const int type, std::string str)
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
if (type == LOG_TYPE_DEBUG) return;
|
||||
#endif // _DEBUG
|
||||
|
||||
#ifdef OUTPUT_DEBUG_API
|
||||
OutputDebugStringA(str.c_str());
|
||||
#endif // OUTPUT_DEBUG_API
|
||||
@ -38,7 +35,7 @@ namespace logger
|
||||
stream << "" << std::put_time(t, "%Y-%m-%d %H:%M:%S") << "\t";
|
||||
#endif // PREPEND_TIMESTAMP
|
||||
|
||||
stream << "[ " << get_type_str(type) << " ] " << str << std::endl;
|
||||
stream << "[ " << LogTypeNames[type] << " ] " << str << std::endl;
|
||||
}
|
||||
|
||||
void write(const int type, const char* fmt, ...)
|
||||
@ -64,6 +61,10 @@ namespace logger
|
||||
public:
|
||||
void pre_start() override
|
||||
{
|
||||
#ifdef REMOVE_PREVIOUS_LOG
|
||||
utils::io::remove_file("project-bo4.log");
|
||||
#endif // REMOVE_PREVIOUS_LOG
|
||||
|
||||
write(LOG_TYPE_INFO, "=======================================================================================================");
|
||||
write(LOG_TYPE_INFO, " Project-BO4 Initializing ... %s[0x%llX]", utils::nt::library{}.get_name().c_str(), utils::nt::library{}.get_ptr());
|
||||
write(LOG_TYPE_INFO, "=======================================================================================================");
|
||||
@ -75,4 +76,4 @@ namespace logger
|
||||
}
|
||||
};
|
||||
}
|
||||
REGISTER_COMPONENT(logger::component)
|
||||
REGISTER_COMPONENT(logger::component)
|
@ -1,22 +1,53 @@
|
||||
#include <std_include.hpp>
|
||||
#include "platform.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/identity.hpp>
|
||||
#include <utils/json_config.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include "WinReg.hpp"
|
||||
#include "definitions/t8_engine.hpp"
|
||||
|
||||
namespace platform
|
||||
{
|
||||
uint64_t bnet_get_userid()
|
||||
{
|
||||
static uint64_t userid = 0;
|
||||
if (!userid)
|
||||
{
|
||||
uint32_t default_xuid = utils::cryptography::xxh32::compute(utils::identity::get_sys_username());
|
||||
userid = utils::json_config::ReadUnsignedInteger("identity", "xuid", default_xuid);
|
||||
}
|
||||
|
||||
return userid;
|
||||
}
|
||||
|
||||
const char* bnet_get_username()
|
||||
{
|
||||
static std::string username{};
|
||||
if (username.empty())
|
||||
{
|
||||
std::string default_name = utils::identity::get_sys_username();
|
||||
username = utils::json_config::ReadString("identity", "name", default_name);
|
||||
}
|
||||
|
||||
return username.data();
|
||||
}
|
||||
|
||||
std::string get_userdata_directory()
|
||||
{
|
||||
return std::format("players/bnet-{}", bnet_get_userid());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//utils::hook::detour BattleNet_API_RequestAppTicket_Hook;
|
||||
//bool BattleNet_API_RequestAppTicket_stub(char* sessionToken, char* accountToken)
|
||||
//{
|
||||
// /* PLACE_HOLDER */
|
||||
//}
|
||||
|
||||
utils::hook::detour PC_TextChat_Print_Hook;
|
||||
void PC_TextChat_Print_Stub(const char* text)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "PC_TextChat_Print(%s)", text);
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_platform_registry()
|
||||
@ -51,16 +82,19 @@ namespace platform
|
||||
utils::hook::set<uint8_t>(0x142307B40_g, 0xC3); // patch#2 Annoying function crashing game; related to BattleNet (TODO : Needs Further Investigation)
|
||||
utils::hook::set<uint32_t>(0x143D08290_g, 0x90C301B0); // patch#3 BattleNet_IsModeAvailable? (patch to mov al,1 retn)
|
||||
|
||||
utils::hook::nop(0x1437DA454_g, 13); // begin cross-auth even without platform being initialized
|
||||
utils::hook::set(0x1444E34C0_g, 0xC301B0); // Checks extended_data and extra_data in json object [bdAuthPC::processPlatformData]
|
||||
utils::hook::nop(0x1437DA454_g, 13); // begin cross-auth even without platform being initialized [LiveConnect_BeginCrossAuthPlatform]
|
||||
utils::hook::set(0x1444D2D60_g, 0xC301B0); // Auth3 Response RSA signature check [bdAuth::validateResponseSignature]
|
||||
utils::hook::set(0x1444E34C0_g, 0xC301B0); // Auth3 Response platform extended data check [bdAuthPC::processPlatformData]
|
||||
|
||||
//PC_TextChat_Print_Hook.create(0x000000000_g, PC_TextChat_Print_Stub); // Disable useless system messages passed into chat box
|
||||
//BattleNet_API_RequestAppTicket_Hook.create(0x000000000_g, BattleNet_API_RequestAppTicket_stub); // Implement custom encryption token
|
||||
}
|
||||
|
||||
int priority() override
|
||||
{
|
||||
return 9996;
|
||||
utils::hook::nop(0x1438994E9_g, 22); // get live name even without platform being initialized [Live_UserSignedIn]
|
||||
utils::hook::nop(0x1438C3476_g, 22); // get live xuid even without platform being initialized [LiveUser_UserGetXuid]
|
||||
|
||||
utils::hook::jump(0x142325C70_g, bnet_get_username); // detour battlenet username
|
||||
utils::hook::jump(0x142325CA0_g, bnet_get_userid); // detour battlenet userid
|
||||
|
||||
//PC_TextChat_Print_Hook.create(0x1422D4A20_g, PC_TextChat_Print_Stub); // Disable useless system messages passed into chat box
|
||||
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ PLATFORM ]: BattleTag: '%s', BattleID: '%llu'", bnet_get_username(), bnet_get_userid());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -2,5 +2,7 @@
|
||||
|
||||
namespace platform
|
||||
{
|
||||
/* PLACE_HOLDER */
|
||||
uint64_t bnet_get_userid();
|
||||
const char* bnet_get_username();
|
||||
std::string get_userdata_directory();
|
||||
}
|
@ -166,8 +166,8 @@ namespace scheduler
|
||||
void post_unpack() override
|
||||
{
|
||||
r_end_frame_hook.create(0x14361E260_g, r_end_frame_stub); // R_EndFrame
|
||||
main_frame_hook.create(0x14288BAE0_g, main_frame_stub); // Com_Frame
|
||||
g_run_frame_hook.create(0x142D08FC0_g, server_frame_stub); // G_RunFrame
|
||||
//main_frame_hook.create(0x14288BAE0_g, main_frame_stub); // Com_Frame
|
||||
//g_run_frame_hook.create(0x142D08FC0_g, server_frame_stub); // G_RunFrame
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
|
@ -125,7 +125,7 @@ namespace discovery
|
||||
|
||||
if (symbols_list.find("com_get_build_version") != symbols_list.end())
|
||||
{
|
||||
const char* build_version = utils::hook::invoke<const char*>(symbols_list["com_get_build_version"]); // Com_GetBuildVersion()
|
||||
const char* build_version = utils::hook::invoke<const char*>(symbols_list["com_get_build_version"]);
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "Address-List Discovery Results for BlackOps4 %s", build_version);
|
||||
}
|
||||
|
||||
@ -163,5 +163,5 @@ namespace discovery
|
||||
}
|
||||
};
|
||||
}
|
||||
REGISTER_COMPONENT(discovery::component)
|
||||
|
||||
//REGISTER_COMPONENT(discovery::component)
|
||||
|
182
source/proxy-dll/demonware/bit_buffer.cpp
Normal file
182
source/proxy-dll/demonware/bit_buffer.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
#include <std_include.hpp>
|
||||
#include "bit_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bool bit_buffer::read_bytes(const unsigned int bytes, unsigned char* output)
|
||||
{
|
||||
return this->read(bytes * 8, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_bool(bool* output)
|
||||
{
|
||||
if (!this->read_data_type(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_uint32(unsigned int* output)
|
||||
{
|
||||
if (!this->read_data_type(8))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->read(32, output);
|
||||
}
|
||||
|
||||
bool bit_buffer::read_data_type(const char expected)
|
||||
{
|
||||
char data_type = 0;
|
||||
|
||||
if (!this->use_data_types_) return true;
|
||||
if (this->read(5, &data_type))
|
||||
{
|
||||
return (data_type == expected);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bytes(const unsigned int bytes, const char* data)
|
||||
{
|
||||
return this->write_bytes(bytes, reinterpret_cast<const unsigned char*>(data));
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bytes(const unsigned int bytes, const unsigned char* data)
|
||||
{
|
||||
return this->write(bytes * 8, data);
|
||||
}
|
||||
|
||||
bool bit_buffer::write_bool(bool data)
|
||||
{
|
||||
if (this->write_data_type(1))
|
||||
{
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_int32(int data)
|
||||
{
|
||||
if (this->write_data_type(7))
|
||||
{
|
||||
return this->write(32, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_uint32(unsigned int data)
|
||||
{
|
||||
if (this->write_data_type(8))
|
||||
{
|
||||
return this->write(32, &data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bit_buffer::write_data_type(char data)
|
||||
{
|
||||
if (!this->use_data_types_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->write(5, &data);
|
||||
}
|
||||
|
||||
bool bit_buffer::read(unsigned int bits, void* output)
|
||||
{
|
||||
if (bits == 0) return false;
|
||||
if ((this->current_bit_ + bits) > (this->buffer_.size() * 8)) return false;
|
||||
|
||||
int cur_byte = this->current_bit_ >> 3;
|
||||
auto cur_out = 0;
|
||||
|
||||
const char* bytes = this->buffer_.data();
|
||||
const auto output_bytes = static_cast<unsigned char*>(output);
|
||||
|
||||
while (bits > 0)
|
||||
{
|
||||
const int min_bit = (bits < 8) ? bits : 8;
|
||||
const auto this_byte = bytes[cur_byte++] & 0xFF;
|
||||
const int remain = this->current_bit_ & 7;
|
||||
|
||||
if ((min_bit + remain) <= 8)
|
||||
{
|
||||
output_bytes[cur_out] = BYTE((0xFF >> (8 - min_bit)) & (this_byte >> remain));
|
||||
}
|
||||
else
|
||||
{
|
||||
output_bytes[cur_out] = BYTE(
|
||||
(0xFF >> (8 - min_bit)) & (bytes[cur_byte] << (8 - remain)) | (this_byte >> remain));
|
||||
}
|
||||
|
||||
cur_out++;
|
||||
this->current_bit_ += min_bit;
|
||||
bits -= min_bit;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bit_buffer::write(const unsigned int bits, const void* data)
|
||||
{
|
||||
if (bits == 0) return false;
|
||||
this->buffer_.resize(this->buffer_.size() + (bits >> 3) + 1);
|
||||
|
||||
int bit = bits;
|
||||
const auto bytes = const_cast<char*>(this->buffer_.data());
|
||||
const auto* input_bytes = static_cast<const unsigned char*>(data);
|
||||
|
||||
while (bit > 0)
|
||||
{
|
||||
const int bit_pos = this->current_bit_ & 7;
|
||||
auto rem_bit = 8 - bit_pos;
|
||||
const auto this_write = (bit < rem_bit) ? bit : rem_bit;
|
||||
|
||||
const BYTE mask = ((0xFF >> rem_bit) | (0xFF << (bit_pos + this_write)));
|
||||
const int byte_pos = this->current_bit_ >> 3;
|
||||
|
||||
const BYTE temp_byte = (mask & bytes[byte_pos]);
|
||||
const BYTE this_bit = ((bits - bit) & 7);
|
||||
const auto this_byte = (bits - bit) >> 3;
|
||||
|
||||
auto this_data = input_bytes[this_byte];
|
||||
|
||||
const auto next_byte = (((bits - 1) >> 3) > this_byte) ? input_bytes[this_byte + 1] : 0;
|
||||
|
||||
this_data = BYTE((next_byte << (8 - this_bit)) | (this_data >> this_bit));
|
||||
|
||||
const BYTE out_byte = (~mask & (this_data << bit_pos) | temp_byte);
|
||||
bytes[byte_pos] = out_byte;
|
||||
|
||||
this->current_bit_ += this_write;
|
||||
bit -= this_write;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bit_buffer::set_use_data_types(const bool use_data_types)
|
||||
{
|
||||
this->use_data_types_ = use_data_types;
|
||||
}
|
||||
|
||||
unsigned int bit_buffer::size() const
|
||||
{
|
||||
return this->current_bit_ / 8 + (this->current_bit_ % 8 ? 1 : 0);
|
||||
}
|
||||
|
||||
std::string& bit_buffer::get_buffer()
|
||||
{
|
||||
this->buffer_.resize(this->size());
|
||||
return this->buffer_;
|
||||
}
|
||||
}
|
40
source/proxy-dll/demonware/bit_buffer.hpp
Normal file
40
source/proxy-dll/demonware/bit_buffer.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bit_buffer final
|
||||
{
|
||||
public:
|
||||
bit_buffer() = default;
|
||||
|
||||
explicit bit_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool read_bytes(unsigned int bytes, unsigned char* output);
|
||||
bool read_bool(bool* output);
|
||||
bool read_uint32(unsigned int* output);
|
||||
bool read_data_type(char expected);
|
||||
|
||||
bool write_bytes(unsigned int bytes, const char* data);
|
||||
bool write_bytes(unsigned int bytes, const unsigned char* data);
|
||||
bool write_bool(bool data);
|
||||
bool write_int32(int data);
|
||||
bool write_uint32(unsigned int data);
|
||||
bool write_data_type(char data);
|
||||
|
||||
bool read(unsigned int bits, void* output);
|
||||
bool write(unsigned int bits, const void* data);
|
||||
|
||||
void set_use_data_types(bool use_data_types);
|
||||
|
||||
unsigned int size() const;
|
||||
|
||||
std::string& get_buffer();
|
||||
|
||||
private:
|
||||
std::string buffer_{};
|
||||
unsigned int current_bit_ = 0;
|
||||
bool use_data_types_ = true;
|
||||
};
|
||||
}
|
365
source/proxy-dll/demonware/byte_buffer.cpp
Normal file
365
source/proxy-dll/demonware/byte_buffer.cpp
Normal file
@ -0,0 +1,365 @@
|
||||
#include <std_include.hpp>
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bool byte_buffer::read_bool(bool* output)
|
||||
{
|
||||
if (!this->read_data_type(1)) return false;
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_byte(char* output)
|
||||
{
|
||||
if (!this->read_data_type(2)) return false;
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_ubyte(unsigned char* output)
|
||||
{
|
||||
if (!this->read_data_type(3)) return false;
|
||||
return this->read(1, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int16(short* output)
|
||||
{
|
||||
if (!this->read_data_type(5)) return false;
|
||||
return this->read(2, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint16(unsigned short* output)
|
||||
{
|
||||
if (!this->read_data_type(6)) return false;
|
||||
return this->read(2, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int32(int* output)
|
||||
{
|
||||
if (!this->read_data_type(7)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint32(unsigned int* output)
|
||||
{
|
||||
if (!this->read_data_type(8)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_int64(__int64* output)
|
||||
{
|
||||
if (!this->read_data_type(9)) return false;
|
||||
return this->read(8, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_uint64(unsigned __int64* output)
|
||||
{
|
||||
if (!this->read_data_type(10)) return false;
|
||||
return this->read(8, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_float(float* output)
|
||||
{
|
||||
if (!this->read_data_type(13)) return false;
|
||||
return this->read(4, output);
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(std::string* output)
|
||||
{
|
||||
char* out_data;
|
||||
if (this->read_string(&out_data))
|
||||
{
|
||||
output->clear();
|
||||
output->append(out_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(char** output)
|
||||
{
|
||||
if (!this->read_data_type(16)) return false;
|
||||
|
||||
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
this->current_byte_ += strlen(*output) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_string(char* output, const int length)
|
||||
{
|
||||
if (!this->read_data_type(16)) return false;
|
||||
|
||||
strcpy_s(output, length, const_cast<char*>(this->buffer_.data()) + this->current_byte_);
|
||||
this->current_byte_ += strlen(output) + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_blob(std::string* output)
|
||||
{
|
||||
char* out_data;
|
||||
int length;
|
||||
if (this->read_blob(&out_data, &length))
|
||||
{
|
||||
output->clear();
|
||||
output->append(out_data, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_blob(char** output, int* length)
|
||||
{
|
||||
if (!this->read_data_type(0x13))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int size;
|
||||
this->read_uint32(&size);
|
||||
|
||||
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
*length = static_cast<int>(size);
|
||||
|
||||
this->current_byte_ += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_struct(std::string* output)
|
||||
{
|
||||
char* out_data;
|
||||
int length;
|
||||
if (this->read_struct(&out_data, &length))
|
||||
{
|
||||
output->clear();
|
||||
output->append(out_data, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_struct(char** output, int* length)
|
||||
{
|
||||
if (!this->read_data_type(0x17))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int size;
|
||||
this->read_uint32(&size);
|
||||
|
||||
*output = const_cast<char*>(this->buffer_.data()) + this->current_byte_;
|
||||
*length = static_cast<int>(size);
|
||||
|
||||
this->current_byte_ += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_data_type(const char expected)
|
||||
{
|
||||
if (!this->use_data_types_) return true;
|
||||
|
||||
char type;
|
||||
this->read(1, &type);
|
||||
return type == expected;
|
||||
}
|
||||
|
||||
bool byte_buffer::read_array_header(const unsigned char expected, unsigned int* element_count,
|
||||
unsigned int* element_size)
|
||||
{
|
||||
if (element_count) *element_count = 0;
|
||||
if (element_size) *element_size = 0;
|
||||
|
||||
if (!this->read_data_type(expected + 100)) return false;
|
||||
|
||||
uint32_t array_size, el_count;
|
||||
if (!this->read_uint32(&array_size)) return false;
|
||||
|
||||
this->set_use_data_types(false);
|
||||
this->read_uint32(&el_count);
|
||||
this->set_use_data_types(true);
|
||||
|
||||
if (element_count) *element_count = el_count;
|
||||
if (element_size) *element_size = array_size / el_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write_bool(bool data)
|
||||
{
|
||||
this->write_data_type(1);
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_byte(char data)
|
||||
{
|
||||
this->write_data_type(2);
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_ubyte(unsigned char data)
|
||||
{
|
||||
this->write_data_type(3);
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int16(short data)
|
||||
{
|
||||
this->write_data_type(5);
|
||||
return this->write(2, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint16(unsigned short data)
|
||||
{
|
||||
this->write_data_type(6);
|
||||
return this->write(2, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int32(int data)
|
||||
{
|
||||
this->write_data_type(7);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint32(unsigned int data)
|
||||
{
|
||||
this->write_data_type(8);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_int64(__int64 data)
|
||||
{
|
||||
this->write_data_type(9);
|
||||
return this->write(8, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_uint64(unsigned __int64 data)
|
||||
{
|
||||
this->write_data_type(10);
|
||||
return this->write(8, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_data_type(char data)
|
||||
{
|
||||
if (!this->use_data_types_) return true;
|
||||
return this->write(1, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_float(float data)
|
||||
{
|
||||
this->write_data_type(13);
|
||||
return this->write(4, &data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_string(const std::string& data)
|
||||
{
|
||||
return this->write_string(data.data());
|
||||
}
|
||||
|
||||
bool byte_buffer::write_string(const char* data)
|
||||
{
|
||||
this->write_data_type(16);
|
||||
return this->write(static_cast<int>(strlen(data)) + 1, data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_blob(const std::string& data)
|
||||
{
|
||||
return this->write_blob(data.data(), INT(data.size()));
|
||||
}
|
||||
|
||||
bool byte_buffer::write_blob(const char* data, const int length)
|
||||
{
|
||||
this->write_data_type(0x13);
|
||||
this->write_uint32(length);
|
||||
|
||||
return this->write(length, data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_struct(const std::string& data)
|
||||
{
|
||||
return this->write_struct(data.data(), INT(data.size()));
|
||||
}
|
||||
|
||||
bool byte_buffer::write_struct(const char* data, const int length)
|
||||
{
|
||||
this->write_data_type(0x17);
|
||||
this->write_uint32(length);
|
||||
|
||||
return this->write(length, data);
|
||||
}
|
||||
|
||||
bool byte_buffer::write_array_header(const unsigned char type, const unsigned int element_count,
|
||||
const unsigned int element_size)
|
||||
{
|
||||
const auto using_types = this->is_using_data_types();
|
||||
this->set_use_data_types(false);
|
||||
|
||||
auto result = this->write_ubyte(type + 100);
|
||||
|
||||
this->set_use_data_types(true);
|
||||
result &= this->write_uint32(element_count * element_size);
|
||||
this->set_use_data_types(false);
|
||||
|
||||
result &= this->write_uint32(element_count);
|
||||
|
||||
this->set_use_data_types(using_types);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool byte_buffer::read(const int bytes, void* output)
|
||||
{
|
||||
if (bytes + this->current_byte_ > this->buffer_.size()) return false;
|
||||
|
||||
std::memmove(output, this->buffer_.data() + this->current_byte_, bytes);
|
||||
this->current_byte_ += bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write(const int bytes, const void* data)
|
||||
{
|
||||
this->buffer_.append(static_cast<const char*>(data), bytes);
|
||||
this->current_byte_ += bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool byte_buffer::write(const std::string& data)
|
||||
{
|
||||
return this->write(static_cast<int>(data.size()), data.data());
|
||||
}
|
||||
|
||||
void byte_buffer::set_use_data_types(const bool use_data_types)
|
||||
{
|
||||
this->use_data_types_ = use_data_types;
|
||||
}
|
||||
|
||||
size_t byte_buffer::size() const
|
||||
{
|
||||
return this->buffer_.size();
|
||||
}
|
||||
|
||||
bool byte_buffer::is_using_data_types() const
|
||||
{
|
||||
return use_data_types_;
|
||||
}
|
||||
|
||||
std::string& byte_buffer::get_buffer()
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
|
||||
std::string byte_buffer::get_remaining()
|
||||
{
|
||||
return std::string(this->buffer_.begin() + this->current_byte_, this->buffer_.end());
|
||||
}
|
||||
|
||||
bool byte_buffer::has_more_data() const
|
||||
{
|
||||
return this->buffer_.size() > this->current_byte_;
|
||||
}
|
||||
}
|
75
source/proxy-dll/demonware/byte_buffer.hpp
Normal file
75
source/proxy-dll/demonware/byte_buffer.hpp
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class byte_buffer final
|
||||
{
|
||||
public:
|
||||
byte_buffer() = default;
|
||||
|
||||
explicit byte_buffer(std::string buffer) : buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
bool read_bool(bool* output);
|
||||
bool read_byte(char* output);
|
||||
bool read_ubyte(unsigned char* output);
|
||||
bool read_int16(short* output);
|
||||
bool read_uint16(unsigned short* output);
|
||||
bool read_int32(int* output);
|
||||
bool read_uint32(unsigned int* output);
|
||||
bool read_int64(__int64* output);
|
||||
bool read_uint64(unsigned __int64* output);
|
||||
bool read_float(float* output);
|
||||
bool read_string(char** output);
|
||||
bool read_string(char* output, int length);
|
||||
bool read_string(std::string* output);
|
||||
bool read_blob(char** output, int* length);
|
||||
bool read_blob(std::string* output);
|
||||
bool read_struct(char** output, int* length);
|
||||
bool read_struct(std::string* output);
|
||||
bool read_data_type(char expected);
|
||||
|
||||
bool read_array_header(unsigned char expected, unsigned int* element_count,
|
||||
unsigned int* element_size = nullptr);
|
||||
|
||||
bool write_bool(bool data);
|
||||
bool write_byte(char data);
|
||||
bool write_ubyte(unsigned char data);
|
||||
bool write_int16(short data);
|
||||
bool write_uint16(unsigned short data);
|
||||
bool write_int32(int data);
|
||||
bool write_uint32(unsigned int data);
|
||||
bool write_int64(__int64 data);
|
||||
bool write_uint64(unsigned __int64 data);
|
||||
bool write_data_type(char data);
|
||||
bool write_float(float data);
|
||||
bool write_string(const char* data);
|
||||
bool write_string(const std::string& data);
|
||||
bool write_blob(const char* data, int length);
|
||||
bool write_blob(const std::string& data);
|
||||
bool write_struct(const char* data, int length);
|
||||
bool write_struct(const std::string& data);
|
||||
|
||||
bool write_array_header(unsigned char type, unsigned int element_count, unsigned int element_size);
|
||||
|
||||
bool read(int bytes, void* output);
|
||||
bool write(int bytes, const void* data);
|
||||
bool write(const std::string& data);
|
||||
|
||||
void set_use_data_types(bool use_data_types);
|
||||
size_t size() const;
|
||||
|
||||
bool is_using_data_types() const;
|
||||
|
||||
std::string& get_buffer();
|
||||
std::string get_remaining();
|
||||
|
||||
bool has_more_data() const;
|
||||
|
||||
private:
|
||||
std::string buffer_;
|
||||
size_t current_byte_ = 0;
|
||||
bool use_data_types_ = true;
|
||||
};
|
||||
}
|
189
source/proxy-dll/demonware/data_types.hpp
Normal file
189
source/proxy-dll/demonware/data_types.hpp
Normal file
@ -0,0 +1,189 @@
|
||||
#pragma once
|
||||
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTaskResult
|
||||
{
|
||||
public:
|
||||
virtual ~bdTaskResult() = default;
|
||||
|
||||
virtual void serialize(byte_buffer*)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void deserialize(byte_buffer*)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class bdTimeStamp final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint32_t unix_time;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint32(this->unix_time);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint32(&this->unix_time);
|
||||
}
|
||||
};
|
||||
|
||||
class bdDMLInfo : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::string country_code; // Char [3]
|
||||
std::string country; // Char [65]
|
||||
std::string region; // Char [65]
|
||||
std::string city; // Char [129]
|
||||
float latitude;
|
||||
float longitude;
|
||||
uint32_t asn; // Autonomous System Number.
|
||||
std::string timezone;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_string(this->country_code);
|
||||
buffer->write_string(this->country);
|
||||
buffer->write_string(this->region);
|
||||
buffer->write_string(this->city);
|
||||
buffer->write_float(this->latitude);
|
||||
buffer->write_float(this->longitude);
|
||||
buffer->write_uint32(this->asn);
|
||||
buffer->write_string(this->timezone);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_string(&this->country_code);
|
||||
buffer->read_string(&this->country);
|
||||
buffer->read_string(&this->region);
|
||||
buffer->read_string(&this->city);
|
||||
buffer->read_float(&this->latitude);
|
||||
buffer->read_float(&this->longitude);
|
||||
buffer->read_uint32(&this->asn);
|
||||
buffer->read_string(&this->timezone);
|
||||
}
|
||||
};
|
||||
|
||||
class bdDMLHierarchicalInfo final : public bdDMLInfo
|
||||
{
|
||||
public:
|
||||
uint32_t m_tier0;
|
||||
uint32_t m_tier1;
|
||||
uint32_t m_tier2;
|
||||
uint32_t m_tier3;
|
||||
uint32_t m_confidence;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
bdDMLInfo::serialize(buffer);
|
||||
|
||||
buffer->write_uint32(this->m_tier0);
|
||||
buffer->write_uint32(this->m_tier1);
|
||||
buffer->write_uint32(this->m_tier2);
|
||||
buffer->write_uint32(this->m_tier3);
|
||||
buffer->write_uint32(this->m_confidence);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
bdDMLInfo::deserialize(buffer);
|
||||
|
||||
buffer->read_uint32(&this->m_tier0);
|
||||
buffer->read_uint32(&this->m_tier1);
|
||||
buffer->read_uint32(&this->m_tier2);
|
||||
buffer->read_uint32(&this->m_tier3);
|
||||
buffer->read_uint32(&this->m_confidence);
|
||||
}
|
||||
};
|
||||
|
||||
class bdStructedDataBuffer final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::string structed_data_protobuffer;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_struct(this->structed_data_protobuffer);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_struct(&this->structed_data_protobuffer);
|
||||
}
|
||||
};
|
||||
|
||||
class bdMarketplaceInventory final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint64_t m_userID;
|
||||
std::string m_accountType;
|
||||
uint32_t m_itemId;
|
||||
uint32_t m_itemQuantity;
|
||||
uint32_t m_itemXp;
|
||||
std::string m_itemData;
|
||||
uint32_t m_expireDateTime;
|
||||
int64_t m_expiryDuration;
|
||||
uint16_t m_collisionField;
|
||||
uint32_t m_modDateTime;
|
||||
uint32_t m_customSourceType;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint64(this->m_userID);
|
||||
buffer->write_string(this->m_accountType);
|
||||
buffer->write_uint32(this->m_itemId);
|
||||
buffer->write_uint32(this->m_itemQuantity);
|
||||
buffer->write_uint32(this->m_itemXp);
|
||||
buffer->write_blob(this->m_itemData);
|
||||
buffer->write_uint32(this->m_expireDateTime);
|
||||
buffer->write_int64(this->m_expiryDuration);
|
||||
buffer->write_uint16(this->m_collisionField);
|
||||
buffer->write_uint32(this->m_modDateTime);
|
||||
buffer->write_uint32(this->m_customSourceType);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint64(&this->m_userID);
|
||||
buffer->read_string(&this->m_accountType);
|
||||
buffer->read_uint32(&this->m_itemId);
|
||||
buffer->read_uint32(&this->m_itemQuantity);
|
||||
buffer->read_uint32(&this->m_itemXp);
|
||||
buffer->read_blob(&this->m_itemData);
|
||||
buffer->read_uint32(&this->m_expireDateTime);
|
||||
buffer->read_int64(&this->m_expiryDuration);
|
||||
buffer->read_uint16(&this->m_collisionField);
|
||||
buffer->read_uint32(&this->m_modDateTime);
|
||||
buffer->read_uint32(&this->m_customSourceType);
|
||||
}
|
||||
};
|
||||
|
||||
class bdPublicProfileInfo final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint64_t m_entityID;
|
||||
int32_t m_VERSION;
|
||||
std::string m_ddl;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint64(this->m_entityID);
|
||||
buffer->write_int32(this->m_VERSION);
|
||||
buffer->write_blob(this->m_ddl);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint64(&this->m_entityID);
|
||||
buffer->read_int32(&this->m_VERSION);
|
||||
buffer->read_blob(&this->m_ddl);
|
||||
}
|
||||
};
|
||||
}
|
141
source/proxy-dll/demonware/keys.cpp
Normal file
141
source/proxy-dll/demonware/keys.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include <std_include.hpp>
|
||||
#include "keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
#include "resource.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
struct data_t
|
||||
{
|
||||
char m_session_key[24];
|
||||
char m_response[8];
|
||||
char m_hmac_key[20];
|
||||
char m_enc_key[16];
|
||||
char m_dec_key[16];
|
||||
} data{};
|
||||
|
||||
std::string packet_buffer;
|
||||
|
||||
void calculate_hmacs(const char* dataxx, const unsigned int data_size,
|
||||
const char* key, const unsigned int key_size,
|
||||
char* dest, const unsigned int dest_size)
|
||||
{
|
||||
char buffer[512];
|
||||
unsigned int pos = 0;
|
||||
unsigned int out_offset = 0;
|
||||
char count = 1;
|
||||
std::string result;
|
||||
|
||||
// buffer add key
|
||||
std::memcpy(&buffer[pos], key, key_size);
|
||||
pos += key_size;
|
||||
|
||||
// buffer add count
|
||||
buffer[pos] = count;
|
||||
pos++;
|
||||
|
||||
// calculate hmac
|
||||
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(dataxx, data_size));
|
||||
|
||||
// save output
|
||||
std::memcpy(dest, result.data(), std::min(20u, (dest_size - out_offset)));
|
||||
out_offset = 20;
|
||||
|
||||
// second loop
|
||||
while (true)
|
||||
{
|
||||
// if we filled the output buffer, exit
|
||||
if (out_offset >= dest_size)
|
||||
break;
|
||||
|
||||
// buffer add last result
|
||||
pos = 0;
|
||||
std::memcpy(&buffer[pos], result.data(), 20);
|
||||
pos += 20;
|
||||
|
||||
// buffer add key
|
||||
std::memcpy(&buffer[pos], key, key_size);
|
||||
pos += key_size;
|
||||
|
||||
// buffer add count
|
||||
count++;
|
||||
buffer[pos] = count;
|
||||
pos++;
|
||||
|
||||
// calculate hmac
|
||||
result = utils::cryptography::hmac_sha1::compute(std::string(buffer, pos), std::string(dataxx, data_size));
|
||||
|
||||
// save output
|
||||
std::memcpy(dest + out_offset, result.data(), std::min(20u, (dest_size - out_offset)));
|
||||
out_offset += 20;
|
||||
}
|
||||
}
|
||||
|
||||
void derive_keys_iw8()
|
||||
{
|
||||
std::string BD_AUTH_TRAFFIC_SIGNING_KEY = utils::nt::load_resource(DW_AUTH_TRAFFIC_SIGNING_KEY);
|
||||
|
||||
const auto packet_hash = utils::cryptography::sha1::compute(packet_buffer);
|
||||
|
||||
char out_1[24];
|
||||
calculate_hmacs(data.m_session_key, 24, BD_AUTH_TRAFFIC_SIGNING_KEY.data(), 294, out_1, 24);
|
||||
|
||||
auto data_3 = utils::cryptography::hmac_sha1::compute(std::string(out_1, 24), packet_hash);
|
||||
|
||||
char out_2[16];
|
||||
calculate_hmacs(data_3.data(), 20, "CLIENTCHAL", 10, out_2, 16);
|
||||
|
||||
char out_3[72];
|
||||
calculate_hmacs(data_3.data(), 20, "BDDATA", 6, out_3, 72);
|
||||
|
||||
|
||||
std::memcpy(data.m_response, &out_2[8], 8);
|
||||
std::memcpy(data.m_hmac_key, &out_3[20], 20);
|
||||
std::memcpy(data.m_dec_key, &out_3[40], 16);
|
||||
std::memcpy(data.m_enc_key, &out_3[56], 16);
|
||||
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] Response id: %s", utils::string::dump_hex(std::string(&out_2[8], 8)).data());
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] Hash verify: %s", utils::string::dump_hex(std::string(&out_3[20], 20)).data());
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] AES dec key: %s", utils::string::dump_hex(std::string(&out_3[40], 16)).data());
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] AES enc key: %s", utils::string::dump_hex(std::string(&out_3[56], 16)).data());
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] Bravo 6, going dark.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void queue_packet_to_hash(const std::string& packet)
|
||||
{
|
||||
packet_buffer.append(packet);
|
||||
}
|
||||
|
||||
void set_session_key(const std::string& key)
|
||||
{
|
||||
std::memcpy(data.m_session_key, key.data(), 24);
|
||||
}
|
||||
|
||||
std::string get_decrypt_key()
|
||||
{
|
||||
return std::string(data.m_dec_key, 16);
|
||||
}
|
||||
|
||||
std::string get_encrypt_key()
|
||||
{
|
||||
return std::string(data.m_enc_key, 16);
|
||||
}
|
||||
|
||||
std::string get_hmac_key()
|
||||
{
|
||||
return std::string(data.m_hmac_key, 20);
|
||||
}
|
||||
|
||||
std::string get_response_id()
|
||||
{
|
||||
return std::string(data.m_response, 8);
|
||||
}
|
||||
}
|
12
source/proxy-dll/demonware/keys.hpp
Normal file
12
source/proxy-dll/demonware/keys.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void derive_keys_iw8();
|
||||
void queue_packet_to_hash(const std::string& packet);
|
||||
void set_session_key(const std::string& key);
|
||||
std::string get_decrypt_key();
|
||||
std::string get_encrypt_key();
|
||||
std::string get_hmac_key();
|
||||
std::string get_response_id();
|
||||
}
|
627
source/proxy-dll/demonware/objects.cpp
Normal file
627
source/proxy-dll/demonware/objects.cpp
Normal file
@ -0,0 +1,627 @@
|
||||
#include <std_include.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <component/platform.hpp>
|
||||
#include "protobuf_helper.hpp"
|
||||
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "resource.hpp"
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
#define PUBLISHER_OBJECTS_ENUMERATE_LPC_DIR
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
std::string HexStringToBinaryString(const std::string& hex_str)
|
||||
{
|
||||
std::string data{};
|
||||
|
||||
for (unsigned int i = 0; i < hex_str.length(); i += 2) {
|
||||
std::string byteString = hex_str.substr(i, 2);
|
||||
char byte = (char)strtol(byteString.c_str(), NULL, 16);
|
||||
data.push_back(byte);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::string get_publisher_file_checksum(std::string file)
|
||||
{
|
||||
std::string file_data;
|
||||
if (!utils::io::read_file(file, &file_data)) return "";
|
||||
|
||||
std::string checksum_md5 = utils::cryptography::md5::compute(file_data);
|
||||
|
||||
return utils::cryptography::base64::encode(checksum_md5);
|
||||
}
|
||||
|
||||
std::vector<objectMetadata> get_publisher_objects_list(const std::string& category)
|
||||
{
|
||||
std::vector<objectMetadata> result;
|
||||
|
||||
#ifdef PUBLISHER_OBJECTS_ENUMERATE_LPC_DIR
|
||||
std::vector<std::string> files = utils::io::list_files("LPC");
|
||||
|
||||
for (std::string file : files)
|
||||
{
|
||||
if (!utils::string::ends_with(file, ".ff")) continue;
|
||||
|
||||
int64_t timestamp = static_cast<int64_t>(time(nullptr));
|
||||
result.push_back({ "treyarch", utils::io::file_name(file), get_publisher_file_checksum(file), utils::io::file_size(file), timestamp, timestamp, "" });
|
||||
}
|
||||
#else // PUBLISHER_OBJECTS_ENUMERATE_CSV_LIST
|
||||
const auto objects_list_csv = utils::nt::load_resource(DW_PUBLISHER_OBJECTS_LIST);
|
||||
std::vector<std::string> items = utils::string::split(objects_list_csv, "\r\n"); // WTF!?
|
||||
|
||||
for (std::string item : items)
|
||||
{
|
||||
std::string checksum = utils::cryptography::base64::encode(HexStringToBinaryString(utils::string::split(item, ',')[2]));
|
||||
std::string name = utils::string::split(item, ',')[0];
|
||||
uint64_t length = std::stoull(utils::string::split(item, ',')[1]);
|
||||
|
||||
int64_t timestamp = static_cast<int64_t>(time(nullptr));
|
||||
result.push_back({ "treyarch", name, checksum, length, timestamp, timestamp, "" });
|
||||
}
|
||||
#endif // PUBLISHER_OBJECTS_ENUMERATE_LPC_DIR
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string generate_publisher_objects_list_json(const std::string& category)
|
||||
{
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("next");
|
||||
json_writer.String("TODO");
|
||||
|
||||
json_writer.Key("nextPageToken");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("objects");
|
||||
json_writer.StartArray();
|
||||
|
||||
std::vector<objectMetadata> objects = get_publisher_objects_list(category);
|
||||
|
||||
for (objectMetadata object : objects)
|
||||
{
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(object.owner);
|
||||
|
||||
json_writer.Key("expiresOn");
|
||||
json_writer.Uint(0);
|
||||
|
||||
json_writer.Key("name");
|
||||
json_writer.String(object.name);
|
||||
|
||||
json_writer.Key("checksum");
|
||||
json_writer.String(object.checksum);
|
||||
|
||||
json_writer.Key("acl");
|
||||
json_writer.String("public");
|
||||
|
||||
json_writer.Key("objectID");
|
||||
json_writer.Uint(0);
|
||||
json_writer.Key("contentID");
|
||||
json_writer.Null();
|
||||
json_writer.Key("objectVersion");
|
||||
json_writer.String("");
|
||||
json_writer.Key("contentVersion");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("contentLength");
|
||||
json_writer.Uint64(object.contentLength);
|
||||
|
||||
json_writer.Key("context");
|
||||
json_writer.String("t8-bnet");
|
||||
|
||||
json_writer.Key("category");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("created");
|
||||
json_writer.Uint64(object.created);
|
||||
|
||||
json_writer.Key("modified");
|
||||
json_writer.Uint64(object.modified);
|
||||
|
||||
json_writer.Key("extraData");
|
||||
json_writer.Null();
|
||||
json_writer.Key("extraDataSize");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryContentLength");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryChecksum");
|
||||
json_writer.Null();
|
||||
json_writer.Key("hasSummary");
|
||||
json_writer.Bool(false);
|
||||
|
||||
json_writer.EndObject();
|
||||
}
|
||||
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string get_user_file_path(const std::string& file)
|
||||
{
|
||||
return std::format("{}/{}", platform::get_userdata_directory(), file);
|
||||
}
|
||||
|
||||
std::string get_user_file_checksum(std::string file_path)
|
||||
{
|
||||
std::string file_data;
|
||||
if (!utils::io::read_file(file_path, &file_data)) return "";
|
||||
|
||||
return std::to_string(utils::cryptography::xxh32::compute(file_data));
|
||||
}
|
||||
|
||||
std::string get_user_file_content(std::string file_path)
|
||||
{
|
||||
std::string file_data;
|
||||
if (!utils::io::read_file(file_path, &file_data)) return "";
|
||||
|
||||
return utils::cryptography::base64::encode(file_data);
|
||||
}
|
||||
|
||||
std::string deliver_user_objects_vectorized_json(std::vector<objectMetadata> requested_items)
|
||||
{
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("objects");
|
||||
json_writer.StartArray();
|
||||
|
||||
for (size_t i = 0; i < requested_items.size(); i++)
|
||||
{
|
||||
if (requested_items[i].contentLength == 0 || requested_items[i].contentURL.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//std::string file_path = get_user_file_path(requested_items[i].owner, requested_items[i].name);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("metadata");
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(requested_items[i].owner.data());
|
||||
|
||||
json_writer.Key("expiresOn");
|
||||
json_writer.Uint(0);
|
||||
|
||||
json_writer.Key("name");
|
||||
json_writer.String(requested_items[i].name.data());
|
||||
|
||||
json_writer.Key("checksum");
|
||||
json_writer.String(requested_items[i].checksum.data());
|
||||
|
||||
json_writer.Key("acl");
|
||||
json_writer.String("public");
|
||||
|
||||
json_writer.Key("objectID");
|
||||
json_writer.Uint(0);
|
||||
json_writer.Key("contentID");
|
||||
json_writer.Null();
|
||||
json_writer.Key("objectVersion");
|
||||
json_writer.String("");
|
||||
json_writer.Key("contentVersion");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("contentLength");
|
||||
json_writer.Uint64(requested_items[i].contentLength);
|
||||
|
||||
json_writer.Key("context");
|
||||
json_writer.String("t8-bnet");
|
||||
|
||||
json_writer.Key("category");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("created");
|
||||
json_writer.Uint64(requested_items[i].created);
|
||||
|
||||
json_writer.Key("modified");
|
||||
json_writer.Uint64(requested_items[i].modified);
|
||||
|
||||
json_writer.Key("extraData");
|
||||
json_writer.Null();
|
||||
json_writer.Key("extraDataSize");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryContentLength");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryChecksum");
|
||||
json_writer.Null();
|
||||
json_writer.Key("hasSummary");
|
||||
json_writer.Bool(false);
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
json_writer.Key("content");
|
||||
json_writer.String(requested_items[i].contentURL.data());
|
||||
|
||||
json_writer.Key("requestIndex");
|
||||
json_writer.Uint64(i);
|
||||
|
||||
json_writer.EndObject();
|
||||
}
|
||||
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.Key("errors");
|
||||
json_writer.StartArray();
|
||||
for (size_t i = 0; i < requested_items.size(); i++)
|
||||
{
|
||||
if (requested_items[i].contentLength == 0 || requested_items[i].contentURL.empty())
|
||||
{
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("requestIndex");
|
||||
json_writer.Uint64(i);
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(requested_items[i].owner.data());
|
||||
json_writer.Key("name");
|
||||
json_writer.String(requested_items[i].name.data());
|
||||
json_writer.Key("error");
|
||||
json_writer.String("Error:ClientError:NotFound");
|
||||
|
||||
json_writer.EndObject();
|
||||
}
|
||||
}
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string deliver_user_objects_vectorized_json(std::vector<objectID> requested_items)
|
||||
{
|
||||
std::vector<objectMetadata> files_metadata_list;
|
||||
|
||||
for (objectID file : requested_items)
|
||||
{
|
||||
std::string file_path = get_user_file_path(file.name);
|
||||
int64_t timestamp = static_cast<int64_t>(time(nullptr));
|
||||
files_metadata_list.push_back({ file.owner, file.name, get_user_file_checksum(file_path), utils::io::file_size(file_path), timestamp, timestamp, get_user_file_content(file_path) });
|
||||
}
|
||||
|
||||
return deliver_user_objects_vectorized_json(files_metadata_list);
|
||||
}
|
||||
|
||||
std::string generate_user_objects_list_json()
|
||||
{
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("nextPageToken");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("next");
|
||||
json_writer.String("TODO");
|
||||
|
||||
json_writer.Key("objects");
|
||||
json_writer.StartArray();
|
||||
|
||||
std::string userdata_directory = platform::get_userdata_directory();
|
||||
|
||||
if (utils::io::directory_exists(userdata_directory))
|
||||
{
|
||||
std::vector<std::string> user_objects = utils::io::list_files(userdata_directory);
|
||||
|
||||
for (std::string object : user_objects)
|
||||
{
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("metadata");
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(std::format("bnet-{}", platform::bnet_get_userid()));
|
||||
|
||||
json_writer.Key("expiresOn");
|
||||
json_writer.Uint(0);
|
||||
|
||||
json_writer.Key("name");
|
||||
json_writer.String(utils::io::file_name(object));
|
||||
|
||||
json_writer.Key("checksum");
|
||||
json_writer.String(get_user_file_checksum(object));
|
||||
|
||||
json_writer.Key("acl");
|
||||
json_writer.String("public");
|
||||
|
||||
json_writer.Key("objectID");
|
||||
json_writer.Uint(0);
|
||||
json_writer.Key("contentID");
|
||||
json_writer.Null();
|
||||
json_writer.Key("objectVersion");
|
||||
json_writer.String("");
|
||||
json_writer.Key("contentVersion");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("contentLength");
|
||||
json_writer.Uint64(utils::io::file_size(object));
|
||||
|
||||
json_writer.Key("context");
|
||||
json_writer.String("t8-bnet");
|
||||
|
||||
json_writer.Key("category");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("created");
|
||||
json_writer.Uint64(static_cast<int64_t>(time(nullptr)));
|
||||
|
||||
json_writer.Key("modified");
|
||||
json_writer.Uint64(static_cast<int64_t>(time(nullptr)));
|
||||
|
||||
json_writer.Key("extraData");
|
||||
json_writer.Null();
|
||||
json_writer.Key("extraDataSize");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryContentLength");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryChecksum");
|
||||
json_writer.Null();
|
||||
json_writer.Key("hasSummary");
|
||||
json_writer.Bool(false);
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
json_writer.Key("tags");
|
||||
json_writer.StartArray();
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.Key("statistics");
|
||||
json_writer.StartArray();
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.EndObject();
|
||||
}
|
||||
}
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string generate_user_objects_count_json()
|
||||
{
|
||||
std::string userdata_directory = platform::get_userdata_directory();
|
||||
|
||||
int files_count = 0;
|
||||
if (utils::io::directory_exists(userdata_directory))
|
||||
{
|
||||
files_count = static_cast<int32_t>(utils::io::list_files(userdata_directory).size());
|
||||
}
|
||||
|
||||
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("total");
|
||||
json_writer.Uint(files_count);
|
||||
|
||||
json_writer.Key("noCategory");
|
||||
json_writer.Uint(files_count);
|
||||
|
||||
json_writer.Key("categories");
|
||||
json_writer.StartObject();
|
||||
json_writer.EndObject();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string construct_file_upload_result_json(const std::string& uploaded_file)
|
||||
{
|
||||
std::string file_path = get_user_file_path(uploaded_file);
|
||||
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("metadata");
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(std::format("bnet-{}", platform::bnet_get_userid()));
|
||||
|
||||
json_writer.Key("expiresOn");
|
||||
json_writer.Uint(0);
|
||||
|
||||
json_writer.Key("name");
|
||||
json_writer.String(uploaded_file);
|
||||
|
||||
json_writer.Key("checksum");
|
||||
json_writer.String(get_user_file_checksum(file_path));
|
||||
|
||||
json_writer.Key("acl");
|
||||
json_writer.String("public");
|
||||
|
||||
json_writer.Key("objectID");
|
||||
json_writer.Uint(0);
|
||||
json_writer.Key("contentID");
|
||||
json_writer.Null();
|
||||
json_writer.Key("objectVersion");
|
||||
json_writer.String("");
|
||||
json_writer.Key("contentVersion");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("contentLength");
|
||||
json_writer.Uint64(utils::io::file_size(file_path));
|
||||
|
||||
json_writer.Key("context");
|
||||
json_writer.String("t8-bnet");
|
||||
|
||||
json_writer.Key("category");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("created");
|
||||
json_writer.Uint64(static_cast<uint32_t>(time(nullptr)));
|
||||
|
||||
json_writer.Key("modified");
|
||||
json_writer.Uint64(static_cast<uint32_t>(time(nullptr)));
|
||||
|
||||
json_writer.Key("extraData");
|
||||
json_writer.Null();
|
||||
json_writer.Key("extraDataSize");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryContentLength");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryChecksum");
|
||||
json_writer.Null();
|
||||
json_writer.Key("hasSummary");
|
||||
json_writer.Bool(false);
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string construct_vectorized_upload_list_json(std::vector<objectMetadata> uploaded_files)
|
||||
{
|
||||
rapidjson::StringBuffer json_buffer{};
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> json_writer(json_buffer);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("objects");
|
||||
json_writer.StartArray();
|
||||
|
||||
for (size_t i = 0; i < uploaded_files.size(); i++)
|
||||
{
|
||||
//std::string file_path = get_user_file_path(requested_items[i].owner, requested_items[i].name);
|
||||
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("metadata");
|
||||
json_writer.StartObject();
|
||||
|
||||
json_writer.Key("owner");
|
||||
json_writer.String(uploaded_files[i].owner.data());
|
||||
|
||||
json_writer.Key("expiresOn");
|
||||
json_writer.Uint(0);
|
||||
|
||||
json_writer.Key("name");
|
||||
json_writer.String(uploaded_files[i].name.data());
|
||||
|
||||
json_writer.Key("checksum");
|
||||
json_writer.String(uploaded_files[i].checksum.data());
|
||||
|
||||
json_writer.Key("acl");
|
||||
json_writer.String("public");
|
||||
|
||||
json_writer.Key("objectID");
|
||||
json_writer.Uint(0);
|
||||
json_writer.Key("contentID");
|
||||
json_writer.Null();
|
||||
json_writer.Key("objectVersion");
|
||||
json_writer.String("");
|
||||
json_writer.Key("contentVersion");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("contentLength");
|
||||
json_writer.Uint64(uploaded_files[i].contentLength);
|
||||
|
||||
json_writer.Key("context");
|
||||
json_writer.String("t8-bnet");
|
||||
|
||||
json_writer.Key("category");
|
||||
json_writer.Null();
|
||||
|
||||
json_writer.Key("created");
|
||||
json_writer.Uint64(uploaded_files[i].created);
|
||||
|
||||
json_writer.Key("modified");
|
||||
json_writer.Uint64(uploaded_files[i].modified);
|
||||
|
||||
json_writer.Key("extraData");
|
||||
json_writer.Null();
|
||||
json_writer.Key("extraDataSize");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryContentLength");
|
||||
json_writer.Null();
|
||||
json_writer.Key("summaryChecksum");
|
||||
json_writer.Null();
|
||||
json_writer.Key("hasSummary");
|
||||
json_writer.Bool(false);
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
json_writer.Key("requestIndex");
|
||||
json_writer.Uint64(i);
|
||||
|
||||
json_writer.EndObject();
|
||||
}
|
||||
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.Key("errors");
|
||||
json_writer.StartArray();
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.Key("validationTokens");
|
||||
json_writer.StartArray();
|
||||
json_writer.EndArray();
|
||||
|
||||
json_writer.EndObject();
|
||||
|
||||
return json_buffer.GetString();
|
||||
}
|
||||
|
||||
std::string construct_vectorized_upload_list_json(std::vector<std::string> uploaded_files)
|
||||
{
|
||||
std::vector<objectMetadata> files_metadata_list;
|
||||
|
||||
for (std::string file : uploaded_files)
|
||||
{
|
||||
std::string file_path = get_user_file_path(file);
|
||||
int64_t timestamp = static_cast<int64_t>(time(nullptr));
|
||||
files_metadata_list.push_back({ std::format("bnet-{}", platform::bnet_get_userid()), file, get_user_file_checksum(file_path), utils::io::file_size(file_path), timestamp, timestamp, get_user_file_content(file_path) });
|
||||
}
|
||||
|
||||
return construct_vectorized_upload_list_json(files_metadata_list);
|
||||
}
|
||||
|
||||
std::string serialize_objectstore_structed_buffer(std::string payload)
|
||||
{
|
||||
bdProtobufHelper header_1st;
|
||||
header_1st.writeString(1, "Content-Length", 16);
|
||||
header_1st.writeString(2, utils::string::va("%u", payload.length()), 8);
|
||||
|
||||
bdProtobufHelper header_2nd;
|
||||
header_2nd.writeString(1, "Authorization", 16);
|
||||
header_2nd.writeString(2, "Bearer project-bo4", 2048);
|
||||
|
||||
|
||||
bdProtobufHelper buffer;
|
||||
buffer.writeString(1, header_1st.buffer.data(), static_cast<uint32_t>(header_1st.buffer.length()));
|
||||
buffer.writeString(1, header_2nd.buffer.data(), static_cast<uint32_t>(header_2nd.buffer.length()));
|
||||
buffer.writeUInt64(2, 200); // Status Code; Anything NON-2XX is Treated as Error
|
||||
buffer.writeString(3, payload.data(), static_cast<uint32_t>(payload.length()));
|
||||
|
||||
return buffer.buffer;
|
||||
}
|
||||
}
|
38
source/proxy-dll/demonware/objects.hpp
Normal file
38
source/proxy-dll/demonware/objects.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
struct objectID
|
||||
{
|
||||
std::string owner;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct objectMetadata
|
||||
{
|
||||
std::string owner;
|
||||
std::string name;
|
||||
std::string checksum;
|
||||
uint64_t contentLength;
|
||||
int64_t created;
|
||||
int64_t modified;
|
||||
std::string contentURL;
|
||||
};
|
||||
|
||||
std::string get_user_file_path(const std::string& file);
|
||||
|
||||
std::string generate_publisher_objects_list_json(const std::string& category);
|
||||
|
||||
std::string construct_file_upload_result_json(const std::string& uploaded_file);
|
||||
|
||||
std::string generate_user_objects_list_json();
|
||||
std::string generate_user_objects_count_json();
|
||||
|
||||
std::string deliver_user_objects_vectorized_json(std::vector<objectMetadata> requested_items);
|
||||
std::string deliver_user_objects_vectorized_json(std::vector<objectID> requested_items);
|
||||
|
||||
std::string construct_vectorized_upload_list_json(std::vector<objectMetadata> uploaded_files);
|
||||
std::string construct_vectorized_upload_list_json(std::vector<std::string> uploaded_files);
|
||||
|
||||
std::string serialize_objectstore_structed_buffer(std::string payload);
|
||||
}
|
110
source/proxy-dll/demonware/protobuf_helper.cpp
Normal file
110
source/proxy-dll/demonware/protobuf_helper.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include <std_include.hpp>
|
||||
#include "protobuf_helper.hpp"
|
||||
#include "ida_defs.h"
|
||||
|
||||
bdProtobufHelper::bdProtobufHelper() {}
|
||||
bdProtobufHelper::~bdProtobufHelper() {}
|
||||
|
||||
/* Yes we unlocked next level of copy-pasta; someone bring the trophy :) */
|
||||
|
||||
bool bdProtobufHelper::encodeVarInt(uint64_t value)
|
||||
{
|
||||
__int64 v2; // rbx
|
||||
unsigned __int64 v4; // rax
|
||||
char v5; // cl
|
||||
char valuea[16]; // [rsp+20h] [rbp-28h] BYREF
|
||||
|
||||
v2 = 0i64;
|
||||
if (value)
|
||||
{
|
||||
do
|
||||
{
|
||||
if ((unsigned int)v2 >= 0xA)
|
||||
break;
|
||||
v4 = value;
|
||||
v5 = value | 0x80;
|
||||
value >>= 7;
|
||||
valuea[v2] = v5;
|
||||
v2 = (unsigned int)(v2 + 1);
|
||||
} while (v4 >= 0x80);
|
||||
valuea[(unsigned int)(v2 - 1)] &= 0x7Fu;
|
||||
}
|
||||
else
|
||||
{
|
||||
valuea[0] = 0;
|
||||
LODWORD(v2) = 1;
|
||||
}
|
||||
//return bdStructSerializationOutputStream::write(stream, valuea, v2) == (_DWORD)v2;
|
||||
this->buffer.append(std::string(valuea, v2));
|
||||
this->length += v2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::encodeVarInt(int64_t value)
|
||||
{
|
||||
unsigned __int64 v2; // rax
|
||||
|
||||
v2 = 2 * value;
|
||||
if (value < 0)
|
||||
v2 = ~v2;
|
||||
return bdProtobufHelper::encodeVarInt(v2);
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::encodeString(const char* value, uint32_t len)
|
||||
{
|
||||
bool result; // al
|
||||
|
||||
result = bdProtobufHelper::encodeVarInt(static_cast<uint64_t>(len));
|
||||
if (result)
|
||||
{
|
||||
this->buffer.append(std::string(value, len));
|
||||
this->length += len;
|
||||
}
|
||||
//result = bdStructSerializationOutputStream::write(stream, value, len) == len;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::encodeTag(uint32_t tagId, eWireType wireType)
|
||||
{
|
||||
unsigned __int64 tag = (int)wireType | (8i64 * tagId);
|
||||
return bdProtobufHelper::encodeVarInt(tag);
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeInt64(uint32_t tag, int64_t value)
|
||||
{
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_VARINT) && bdProtobufHelper::encodeVarInt(value);
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeUInt64(uint32_t tag, uint64_t value)
|
||||
{
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_VARINT) && bdProtobufHelper::encodeVarInt(value);
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeInt32(uint32_t tag, int32_t value)
|
||||
{
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_VARINT) && bdProtobufHelper::encodeVarInt(static_cast<int64_t>(value));
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeUInt32(uint32_t tag, uint32_t value)
|
||||
{
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_VARINT) && bdProtobufHelper::encodeVarInt(static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeString(uint32_t tag, const char* value, uint32_t size)
|
||||
{
|
||||
unsigned int v5; // edi
|
||||
const void* v8; // rax
|
||||
|
||||
v5 = size;
|
||||
v8 = memchr(value, 0, size);
|
||||
if (v8)
|
||||
v5 = (_DWORD)v8 - (_DWORD)value;
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_STRING) && bdProtobufHelper::encodeString(value, v5);
|
||||
}
|
||||
|
||||
bool bdProtobufHelper::writeBlob(uint32_t tag, void* buffer, uint32_t size)
|
||||
{
|
||||
return bdProtobufHelper::encodeTag(tag, WIRETYPE_STRING) && bdProtobufHelper::encodeString(reinterpret_cast<const char*>(buffer), size);
|
||||
}
|
38
source/proxy-dll/demonware/protobuf_helper.hpp
Normal file
38
source/proxy-dll/demonware/protobuf_helper.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
enum eWireType
|
||||
{
|
||||
WIRETYPE_VARINT = 0,
|
||||
WIRETYPE_64BIT = 1,
|
||||
WIRETYPE_STRING = 2,
|
||||
WIRETYPE_32BIT = 5,
|
||||
WIRETYPE_INVALID = -1
|
||||
};
|
||||
|
||||
class bdProtobufHelper
|
||||
{
|
||||
public:
|
||||
std::string buffer{};
|
||||
uint32_t length{};
|
||||
|
||||
bdProtobufHelper();
|
||||
~bdProtobufHelper();
|
||||
|
||||
bool write(const void* value, uint32_t byteCount);
|
||||
bool writeString(uint32_t tag, const char* value, uint32_t size);
|
||||
bool writeBlob(uint32_t tag, void* buffer, uint32_t size);
|
||||
bool writeInt64(uint32_t tag, int64_t value);
|
||||
bool writeUInt64(uint32_t tag, uint64_t value);
|
||||
bool writeInt32(uint32_t tag, int32_t value);
|
||||
bool writeUInt32(uint32_t tag, uint32_t value);
|
||||
|
||||
|
||||
private:
|
||||
bool encodeTag(uint32_t tagId, eWireType wireType);
|
||||
bool encodeVarInt(int64_t value);
|
||||
bool encodeVarInt(uint64_t value);
|
||||
bool encodeString(const char* value, uint32_t len);
|
||||
|
||||
|
||||
};
|
87
source/proxy-dll/demonware/reply.cpp
Normal file
87
source/proxy-dll/demonware/reply.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <std_include.hpp>
|
||||
#include "keys.hpp"
|
||||
#include "reply.hpp"
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
std::string unencrypted_reply::data()
|
||||
{
|
||||
byte_buffer result;
|
||||
result.set_use_data_types(false);
|
||||
|
||||
result.write_int32(static_cast<int>(this->buffer_.size()) + 2);
|
||||
result.write_bool(false);
|
||||
result.write_ubyte(this->type());
|
||||
result.write(this->buffer_);
|
||||
|
||||
return result.get_buffer();
|
||||
}
|
||||
|
||||
std::string encrypted_reply::data()
|
||||
{
|
||||
byte_buffer result;
|
||||
result.set_use_data_types(false);
|
||||
|
||||
byte_buffer enc_buffer;
|
||||
enc_buffer.set_use_data_types(false);
|
||||
|
||||
enc_buffer.write_uint32(static_cast<unsigned int>(this->buffer_.size())); // service data size CHECKTHIS!!
|
||||
enc_buffer.write_ubyte(this->type()); // TASK_REPLY type
|
||||
enc_buffer.write(this->buffer_); // service data
|
||||
|
||||
auto aligned_data = enc_buffer.get_buffer();
|
||||
auto size = aligned_data.size();
|
||||
size = ~15 & (size + 15); // 16 byte align
|
||||
aligned_data.resize(size);
|
||||
|
||||
// seed
|
||||
std::string seed("\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED\x5E\xED", 16);
|
||||
|
||||
// encrypt
|
||||
const auto enc_data = utils::cryptography::aes::encrypt(aligned_data, seed, demonware::get_encrypt_key());
|
||||
|
||||
// header : encrypted service data : hash
|
||||
static auto msg_count = 0;
|
||||
msg_count++;
|
||||
|
||||
byte_buffer response;
|
||||
response.set_use_data_types(false);
|
||||
|
||||
response.write_int32(30 + static_cast<int>(enc_data.size()));
|
||||
response.write_ubyte(static_cast<unsigned char>(0xAB));
|
||||
response.write_ubyte(static_cast<unsigned char>(0x85));
|
||||
response.write_int32(msg_count);
|
||||
response.write(16, seed.data());
|
||||
response.write(enc_data);
|
||||
|
||||
// hash entire packet and append end
|
||||
auto hash_data = utils::cryptography::hmac_sha1::compute(response.get_buffer(), demonware::get_hmac_key());
|
||||
hash_data.resize(8);
|
||||
response.write(8, hash_data.data());
|
||||
|
||||
return response.get_buffer();
|
||||
}
|
||||
|
||||
void remote_reply::send(bit_buffer* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||
|
||||
this->server_->send_reply(reply.get());
|
||||
}
|
||||
|
||||
void remote_reply::send(byte_buffer* buffer, const bool encrypted)
|
||||
{
|
||||
std::unique_ptr<typed_reply> reply;
|
||||
|
||||
if (encrypted) reply = std::make_unique<encrypted_reply>(this->type_, buffer);
|
||||
else reply = std::make_unique<unencrypted_reply>(this->type_, buffer);
|
||||
|
||||
this->server_->send_reply(reply.get());
|
||||
}
|
||||
}
|
198
source/proxy-dll/demonware/reply.hpp
Normal file
198
source/proxy-dll/demonware/reply.hpp
Normal file
@ -0,0 +1,198 @@
|
||||
#pragma once
|
||||
|
||||
#include "bit_buffer.hpp"
|
||||
#include "byte_buffer.hpp"
|
||||
#include "data_types.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class reply
|
||||
{
|
||||
public:
|
||||
reply() = default;
|
||||
|
||||
reply(reply&&) = delete;
|
||||
reply(const reply&) = delete;
|
||||
reply& operator=(reply&&) = delete;
|
||||
reply& operator=(const reply&) = delete;
|
||||
|
||||
virtual ~reply() = default;
|
||||
virtual std::string data() = 0;
|
||||
};
|
||||
|
||||
class raw_reply : public reply
|
||||
{
|
||||
protected:
|
||||
std::string buffer_;
|
||||
|
||||
public:
|
||||
raw_reply() = default;
|
||||
|
||||
explicit raw_reply(std::string data) : buffer_(std::move(data))
|
||||
{
|
||||
}
|
||||
|
||||
std::string data() override
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
};
|
||||
|
||||
class typed_reply : public raw_reply
|
||||
{
|
||||
public:
|
||||
typed_reply(const uint8_t _type) : type_(_type)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t type() const { return this->type_; }
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
};
|
||||
|
||||
class encrypted_reply final : public typed_reply
|
||||
{
|
||||
public:
|
||||
encrypted_reply(const uint8_t type, bit_buffer* bbuffer) : typed_reply(type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
encrypted_reply(const uint8_t type, byte_buffer* bbuffer) : typed_reply(type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
std::string data() override;
|
||||
};
|
||||
|
||||
class unencrypted_reply final : public typed_reply
|
||||
{
|
||||
public:
|
||||
unencrypted_reply(const uint8_t _type, bit_buffer* bbuffer) : typed_reply(_type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
unencrypted_reply(const uint8_t _type, byte_buffer* bbuffer) : typed_reply(_type)
|
||||
{
|
||||
this->buffer_.append(bbuffer->get_buffer());
|
||||
}
|
||||
|
||||
std::string data() override;
|
||||
};
|
||||
|
||||
class service_server;
|
||||
|
||||
class remote_reply final
|
||||
{
|
||||
public:
|
||||
remote_reply(service_server* server, uint8_t _type) : type_(_type), server_(server)
|
||||
{
|
||||
}
|
||||
|
||||
void send(bit_buffer* buffer, bool encrypted);
|
||||
void send(byte_buffer* buffer, bool encrypted);
|
||||
|
||||
uint8_t type() const { return this->type_; }
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
service_server* server_;
|
||||
};
|
||||
|
||||
class service_reply final
|
||||
{
|
||||
public:
|
||||
service_reply(service_server* _server, const uint8_t _type, const uint32_t _error, const bool _structed)
|
||||
: type_(_type), error_(_error), structed_(_structed), reply_(_server, 1)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t send()
|
||||
{
|
||||
static uint64_t id = 0x0000000000000000;
|
||||
const auto transaction_id = ++id;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.write_uint64(transaction_id);
|
||||
buffer.write_uint32(this->error_);
|
||||
buffer.write_ubyte(this->type_);
|
||||
|
||||
if (!this->error_)
|
||||
{
|
||||
if (!structed_)
|
||||
{
|
||||
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||
if (!this->objects_.empty())
|
||||
{
|
||||
buffer.write_uint32(uint32_t(this->objects_.size()));
|
||||
|
||||
for (auto& object : this->objects_)
|
||||
{
|
||||
object->serialize(&buffer);
|
||||
}
|
||||
|
||||
this->objects_.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this->objects_.empty())
|
||||
{
|
||||
this->objects_[0]->serialize(&buffer);
|
||||
this->objects_.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.write_uint64(transaction_id);
|
||||
}
|
||||
|
||||
this->reply_.send(&buffer, true);
|
||||
return transaction_id;
|
||||
}
|
||||
|
||||
void add(const std::shared_ptr<bdTaskResult>& object)
|
||||
{
|
||||
this->objects_.push_back(object);
|
||||
}
|
||||
|
||||
void add(bdTaskResult* object)
|
||||
{
|
||||
this->add(std::shared_ptr<bdTaskResult>(object));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t type_;
|
||||
uint32_t error_;
|
||||
bool structed_;
|
||||
remote_reply reply_;
|
||||
std::vector<std::shared_ptr<bdTaskResult>> objects_;
|
||||
};
|
||||
|
||||
class structure_reply final
|
||||
{
|
||||
public:
|
||||
structure_reply(service_server* _server, const uint8_t _type)
|
||||
: reply_(_server, _type, 0, 1)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t send(const std::string& buffer)
|
||||
{
|
||||
auto result = new bdStructedDataBuffer;
|
||||
result->structed_data_protobuffer = buffer;
|
||||
|
||||
this->reply_.add(result);
|
||||
|
||||
return this->reply_.send();
|
||||
}
|
||||
|
||||
private:
|
||||
service_reply reply_;
|
||||
};
|
||||
}
|
60
source/proxy-dll/demonware/server_registry.hpp
Normal file
60
source/proxy-dll/demonware/server_registry.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "servers/base_server.hpp"
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
template <typename T>
|
||||
class server_registry
|
||||
{
|
||||
static_assert(std::is_base_of<base_server, T>::value, "Invalid server registry type");
|
||||
|
||||
public:
|
||||
template <typename S, typename ...Args>
|
||||
void create(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<T, S>::value, "Invalid server type");
|
||||
|
||||
auto server = std::make_unique<S>(std::forward<Args>(args)...);
|
||||
const auto address = server->get_address();
|
||||
servers_[address] = std::move(server);
|
||||
}
|
||||
|
||||
void for_each(const std::function<void(T&)>& callback) const
|
||||
{
|
||||
for (auto& server : servers_)
|
||||
{
|
||||
callback(*server.second);
|
||||
}
|
||||
}
|
||||
|
||||
T* find(const std::string& name)
|
||||
{
|
||||
const auto address = utils::cryptography::jenkins_one_at_a_time::compute(name);
|
||||
return find(address);
|
||||
}
|
||||
|
||||
T* find(const uint32_t address)
|
||||
{
|
||||
const auto it = servers_.find(address);
|
||||
if (it == servers_.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
void frame()
|
||||
{
|
||||
for (auto& server : servers_)
|
||||
{
|
||||
server.second->frame();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<uint32_t, std::unique_ptr<T>> servers_;
|
||||
};
|
||||
}
|
185
source/proxy-dll/demonware/servers/auth3_server.cpp
Normal file
185
source/proxy-dll/demonware/servers/auth3_server.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "auth3_server.hpp"
|
||||
#include "../keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct auth_ticket
|
||||
{
|
||||
unsigned int m_magicNumber;
|
||||
char m_type;
|
||||
unsigned int m_titleID;
|
||||
unsigned int m_timeIssued;
|
||||
unsigned int m_timeExpires;
|
||||
unsigned __int64 m_licenseID;
|
||||
unsigned __int64 m_userID;
|
||||
char m_username[64];
|
||||
char m_sessionKey[24];
|
||||
char m_usingHashMagicNumber[3];
|
||||
char m_hash[4];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
|
||||
void auth3_server::send_reply(reply* data)
|
||||
{
|
||||
if (!data) return;
|
||||
this->send(data->data());
|
||||
}
|
||||
|
||||
void auth3_server::handle(const std::string& packet)
|
||||
{
|
||||
if (packet.starts_with("POST /auth/"))
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [auth]: user requested authentication.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int title_id = 0;
|
||||
unsigned int iv_seed = 0;
|
||||
std::string identity{};
|
||||
std::string session_token{};
|
||||
std::string account_token{};
|
||||
|
||||
rapidjson::Document j;
|
||||
j.Parse(packet.data(), packet.size());
|
||||
|
||||
if (j.HasMember("title_id") && j["title_id"].IsString())
|
||||
{
|
||||
title_id = std::stoul(j["title_id"].GetString());
|
||||
}
|
||||
|
||||
if (j.HasMember("iv_seed") && j["iv_seed"].IsString())
|
||||
{
|
||||
iv_seed = std::stoul(j["iv_seed"].GetString());
|
||||
}
|
||||
|
||||
if (j.HasMember("identity") && j["identity"].IsString())
|
||||
{
|
||||
identity = j["identity"].GetString();
|
||||
}
|
||||
|
||||
if (j.HasMember("extra_data") && j["extra_data"].IsString())
|
||||
{
|
||||
rapidjson::Document extra_data;
|
||||
auto& ed = j["extra_data"];
|
||||
extra_data.Parse(ed.GetString(), ed.GetStringLength());
|
||||
|
||||
if (extra_data.HasMember("session_token") && extra_data["session_token"].IsString())
|
||||
{
|
||||
auto& token_field = extra_data["session_token"];
|
||||
std::string token_b64(token_field.GetString(), token_field.GetStringLength());
|
||||
session_token = token_b64;
|
||||
}
|
||||
if (extra_data.HasMember("account_token") && extra_data["account_token"].IsString())
|
||||
{
|
||||
auto& token_field = extra_data["account_token"];
|
||||
std::string token_b64(token_field.GetString(), token_field.GetStringLength());
|
||||
account_token = utils::cryptography::base64::decode(token_b64);
|
||||
}
|
||||
}
|
||||
|
||||
std::string session_key(
|
||||
"\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24);
|
||||
|
||||
// client_ticket
|
||||
auth_ticket ticket{};
|
||||
std::memset(&ticket, 0x0, sizeof ticket);
|
||||
ticket.m_magicNumber = 0xEFBDADDE;
|
||||
ticket.m_type = 0;
|
||||
ticket.m_titleID = title_id;
|
||||
ticket.m_timeIssued = static_cast<uint32_t>(time(nullptr));
|
||||
ticket.m_timeExpires = ticket.m_timeIssued + 30000;
|
||||
ticket.m_licenseID = 0;
|
||||
ticket.m_userID = 0;
|
||||
strncpy_s(ticket.m_username, sizeof(ticket.m_username), session_token.data(), session_token.length());
|
||||
std::memcpy(ticket.m_sessionKey, session_key.data(), 24);
|
||||
|
||||
const auto client_ticket_b64 = utils::cryptography::base64::encode(reinterpret_cast<const unsigned char*>(&ticket), sizeof(ticket));
|
||||
|
||||
// server_ticket
|
||||
uint8_t server_ticket[128];
|
||||
std::memset(&server_ticket, 0, sizeof server_ticket);
|
||||
std::memcpy(server_ticket, session_key.data(), 24);
|
||||
const auto server_ticket_b64 = utils::cryptography::base64::encode(server_ticket, 128);
|
||||
|
||||
demonware::set_session_key(session_key);
|
||||
|
||||
// header time
|
||||
char date[64];
|
||||
const auto now = time(nullptr);
|
||||
tm gmtm{};
|
||||
gmtime_s(&gmtm, &now);
|
||||
strftime(date, 64, "%a, %d %b %G %T", &gmtm);
|
||||
|
||||
rapidjson::Document extra;
|
||||
extra.SetObject();
|
||||
|
||||
std::string username = std::string(ticket.m_username, sizeof(ticket.m_username)).data();
|
||||
extra.AddMember("username", username, extra.GetAllocator());
|
||||
extra.AddMember("time_to_live", 9999, extra.GetAllocator());
|
||||
|
||||
const auto lul = utils::cryptography::base64::encode("lul");
|
||||
extra.AddMember("extended_data", lul, extra.GetAllocator());
|
||||
|
||||
rapidjson::StringBuffer extra_buffer{};
|
||||
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<>>
|
||||
extra_writer(extra_buffer);
|
||||
extra.Accept(extra_writer);
|
||||
|
||||
std::string extra_data{};
|
||||
extra_data.append(extra_buffer.GetString(), extra_buffer.GetLength());
|
||||
// json content
|
||||
rapidjson::Document doc;
|
||||
doc.SetObject();
|
||||
|
||||
doc.AddMember("auth_task", "85", doc.GetAllocator());
|
||||
doc.AddMember("code", "700", doc.GetAllocator());
|
||||
|
||||
auto seed = std::to_string(iv_seed);
|
||||
doc.AddMember("iv_seed", seed, doc.GetAllocator());
|
||||
doc.AddMember("client_ticket", client_ticket_b64, doc.GetAllocator());
|
||||
doc.AddMember("server_ticket", server_ticket_b64, doc.GetAllocator());
|
||||
doc.AddMember("client_id", "treyarch-cod-t8-bnet", doc.GetAllocator());
|
||||
doc.AddMember("account_type", "bnet", doc.GetAllocator());
|
||||
doc.AddMember("crossplay_enabled", false, doc.GetAllocator());
|
||||
doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator());
|
||||
doc.AddMember("identity", identity, doc.GetAllocator());
|
||||
doc.AddMember("extra_data", extra_data, doc.GetAllocator());
|
||||
doc.AddMember("service_level", "paid", doc.GetAllocator());
|
||||
|
||||
rapidjson::Value value{};
|
||||
doc.AddMember("lsg_endpoint", value, doc.GetAllocator());
|
||||
|
||||
rapidjson::StringBuffer buffer{};
|
||||
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<>>
|
||||
writer(buffer);
|
||||
doc.Accept(writer);
|
||||
|
||||
// http stuff
|
||||
std::string result;
|
||||
result.append("HTTP/1.1 200 OK\r\n");
|
||||
result.append("Server: TornadoServer/4.5.3\r\n");
|
||||
result.append("Content-Type: application/json\r\n");
|
||||
result.append(utils::string::va("Date: %s GMT\r\n", date));
|
||||
result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength()));
|
||||
result.append(buffer.GetString(), buffer.GetLength());
|
||||
|
||||
raw_reply reply(result);
|
||||
|
||||
this->send_reply(&reply);
|
||||
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [auth]: user successfully authenticated.");
|
||||
#endif
|
||||
}
|
||||
}
|
16
source/proxy-dll/demonware/servers/auth3_server.hpp
Normal file
16
source/proxy-dll/demonware/servers/auth3_server.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "tcp_server.hpp"
|
||||
#include "../reply.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class auth3_server : public tcp_server
|
||||
{
|
||||
public:
|
||||
using tcp_server::tcp_server;
|
||||
|
||||
private:
|
||||
void send_reply(reply* data);
|
||||
void handle(const std::string& packet) override;
|
||||
};
|
||||
}
|
22
source/proxy-dll/demonware/servers/base_server.cpp
Normal file
22
source/proxy-dll/demonware/servers/base_server.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <std_include.hpp>
|
||||
#include "base_server.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
base_server::base_server(std::string name): name_(std::move(name))
|
||||
{
|
||||
this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_);
|
||||
}
|
||||
|
||||
const std::string& base_server::get_name() const
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
uint32_t base_server::get_address() const
|
||||
{
|
||||
return this->address_;
|
||||
}
|
||||
}
|
30
source/proxy-dll/demonware/servers/base_server.hpp
Normal file
30
source/proxy-dll/demonware/servers/base_server.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class base_server
|
||||
{
|
||||
public:
|
||||
using stream_queue = std::queue<char>;
|
||||
using data_queue = std::queue<std::string>;
|
||||
|
||||
base_server(std::string name);
|
||||
|
||||
base_server(base_server&&) = delete;
|
||||
base_server(const base_server&) = delete;
|
||||
base_server& operator=(base_server&&) = delete;
|
||||
base_server& operator=(const base_server&) = delete;
|
||||
|
||||
virtual ~base_server() = default;
|
||||
|
||||
const std::string& get_name() const;
|
||||
|
||||
uint32_t get_address() const;
|
||||
|
||||
virtual void frame() = 0;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::uint32_t address_ = 0;
|
||||
};
|
||||
}
|
181
source/proxy-dll/demonware/servers/lobby_server.cpp
Normal file
181
source/proxy-dll/demonware/servers/lobby_server.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <std_include.hpp>
|
||||
#include "lobby_server.hpp"
|
||||
|
||||
#include "../services.hpp"
|
||||
#include "../keys.hpp"
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
lobby_server::lobby_server(std::string name) : tcp_server(std::move(name))
|
||||
{
|
||||
this->register_service<bdStats>();
|
||||
this->register_service<bdProfiles>();
|
||||
this->register_service<bdTitleUtilities>();
|
||||
this->register_service<bdKeyArchive>();
|
||||
this->register_service<bdBandwidthTest>();
|
||||
this->register_service<bdCounter>();
|
||||
this->register_service<bdDML>();
|
||||
this->register_service<bdGroup>();
|
||||
this->register_service<bdAnticheat>();
|
||||
this->register_service<bdTags>();
|
||||
this->register_service<bdPooledStorage>();
|
||||
this->register_service<bdEventLog>();
|
||||
this->register_service<bdRichPresence>();
|
||||
this->register_service<bdMarketplace>();
|
||||
this->register_service<bdPublisherVariables>();
|
||||
this->register_service<bdMarketingComms>();
|
||||
this->register_service<bdUNK125>();
|
||||
this->register_service<bdObjectStore>();
|
||||
this->register_service<bdLootGeneration>();
|
||||
};
|
||||
|
||||
void lobby_server::send_reply(reply* data)
|
||||
{
|
||||
if (!data) return;
|
||||
this->send(data->data());
|
||||
}
|
||||
|
||||
void lobby_server::handle(const std::string& packet)
|
||||
{
|
||||
byte_buffer buffer(packet);
|
||||
buffer.set_use_data_types(false);
|
||||
|
||||
try
|
||||
{
|
||||
while (buffer.has_more_data())
|
||||
{
|
||||
int size;
|
||||
buffer.read_int32(&size);
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
const std::string zero("\x00\x00\x00\x00", 4);
|
||||
raw_reply reply(zero);
|
||||
this->send_reply(&reply);
|
||||
return;
|
||||
}
|
||||
else if (size == 0xC8)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: received client_header_ack.");
|
||||
#endif
|
||||
|
||||
int c8;
|
||||
buffer.read_int32(&c8);
|
||||
std::string packet_1 = buffer.get_remaining();
|
||||
demonware::queue_packet_to_hash(packet_1);
|
||||
|
||||
/* msgType[BYTE] serverSelectedProto[DWORD] cypher210ConnID[QWORD] serverNonce[QWORD] */
|
||||
/* 0x81(129) 0xD2(210) 0x3713371337133713 0x3713371337133713 */
|
||||
|
||||
const std::string packet_2(
|
||||
"\x16\x00\x00\x00\xab\x81\xd2\x00\x00\x00\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37",
|
||||
26);
|
||||
demonware::queue_packet_to_hash(packet_2);
|
||||
|
||||
raw_reply reply(packet_2);
|
||||
this->send_reply(&reply);
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: sending server_header_ack.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.size() < size_t(size)) return;
|
||||
|
||||
uint8_t check_ab;
|
||||
buffer.read_ubyte(&check_ab);
|
||||
if (check_ab == 0xAB)
|
||||
{
|
||||
uint8_t type;
|
||||
buffer.read_ubyte(&type);
|
||||
|
||||
if (type == 0x82)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: received client_auth.");
|
||||
#endif
|
||||
std::string packet_3(packet.data(), packet.size() - 8); // this 8 are client hash check?
|
||||
|
||||
demonware::queue_packet_to_hash(packet_3);
|
||||
demonware::derive_keys_iw8();
|
||||
|
||||
char buff[14] = "\x0A\x00\x00\x00\xAB\x83";
|
||||
std::memcpy(&buff[6], demonware::get_response_id().data(), 8);
|
||||
std::string response(buff, 14);
|
||||
|
||||
raw_reply reply(response);
|
||||
this->send_reply(&reply);
|
||||
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: sending server_auth_done.");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (type == 0x85)
|
||||
{
|
||||
uint32_t msg_count;
|
||||
buffer.read_uint32(&msg_count);
|
||||
|
||||
char seed[16];
|
||||
buffer.read(16, &seed);
|
||||
|
||||
std::string enc = buffer.get_remaining();
|
||||
|
||||
char hash[8];
|
||||
std::memcpy(hash, &(enc.data()[enc.size() - 8]), 8);
|
||||
|
||||
std::string dec = utils::cryptography::aes::decrypt(
|
||||
std::string(enc.data(), enc.size() - 8), std::string(seed, 16),
|
||||
demonware::get_decrypt_key());
|
||||
|
||||
byte_buffer serv(dec);
|
||||
serv.set_use_data_types(false);
|
||||
|
||||
uint32_t serv_size;
|
||||
serv.read_uint32(&serv_size);
|
||||
|
||||
uint8_t magic; // 0x86
|
||||
serv.read_ubyte(&magic);
|
||||
|
||||
uint8_t service_id;
|
||||
serv.read_ubyte(&service_id);
|
||||
|
||||
this->call_service(service_id, serv.get_remaining());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: ERROR! received unk message.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void lobby_server::call_service(const uint8_t id, const std::string& data)
|
||||
{
|
||||
const auto& it = this->services_.find(id);
|
||||
|
||||
if (it != this->services_.end())
|
||||
{
|
||||
it->second->exec_task(this, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [lobby]: missing service '%s'", utils::string::va("%d", id));
|
||||
|
||||
// return no error
|
||||
byte_buffer buffer(data);
|
||||
uint8_t task_id;
|
||||
buffer.read_ubyte(&task_id);
|
||||
|
||||
this->create_reply(task_id)->send();
|
||||
}
|
||||
}
|
||||
}
|
33
source/proxy-dll/demonware/servers/lobby_server.hpp
Normal file
33
source/proxy-dll/demonware/servers/lobby_server.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "tcp_server.hpp"
|
||||
#include "service_server.hpp"
|
||||
#include "../service.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class lobby_server : public tcp_server, service_server
|
||||
{
|
||||
public:
|
||||
lobby_server(std::string name);
|
||||
|
||||
template <typename T>
|
||||
void register_service()
|
||||
{
|
||||
static_assert(std::is_base_of<service, T>::value, "service must inherit from service");
|
||||
|
||||
auto service = std::make_unique<T>();
|
||||
const uint8_t id = service->id();
|
||||
|
||||
this->services_[id] = std::move(service);
|
||||
}
|
||||
|
||||
void send_reply(reply* data) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<uint8_t, std::unique_ptr<service>> services_;
|
||||
|
||||
void handle(const std::string& packet) override;
|
||||
void call_service(uint8_t id, const std::string& data);
|
||||
};
|
||||
}
|
33
source/proxy-dll/demonware/servers/service_server.hpp
Normal file
33
source/proxy-dll/demonware/servers/service_server.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "../reply.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class service_server
|
||||
{
|
||||
public:
|
||||
virtual ~service_server() = default;
|
||||
|
||||
virtual std::shared_ptr<remote_reply> create_message(uint8_t type)
|
||||
{
|
||||
auto reply = std::make_shared<remote_reply>(this, type);
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
||||
virtual std::shared_ptr<service_reply> create_reply(uint8_t type, uint32_t error = 0)
|
||||
{
|
||||
auto reply = std::make_shared<service_reply>(this, type, error, false);
|
||||
return reply;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<structure_reply> create_structed_reply(uint8_t type)
|
||||
{
|
||||
auto reply = std::make_shared<structure_reply>(this, type);
|
||||
return reply;
|
||||
}
|
||||
|
||||
virtual void send_reply(reply* data) = 0;
|
||||
};
|
||||
}
|
62
source/proxy-dll/demonware/servers/stun_server.cpp
Normal file
62
source/proxy-dll/demonware/servers/stun_server.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <std_include.hpp>
|
||||
#include "stun_server.hpp"
|
||||
|
||||
#include "../byte_buffer.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void stun_server::handle(const endpoint_data& endpoint, const std::string& packet)
|
||||
{
|
||||
uint8_t type, version, padding;
|
||||
|
||||
byte_buffer buffer(packet);
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.read_ubyte(&type);
|
||||
buffer.read_ubyte(&version);
|
||||
buffer.read_ubyte(&padding);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 30:
|
||||
this->ip_discovery(endpoint);
|
||||
break;
|
||||
case 20:
|
||||
this->nat_discovery(endpoint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void stun_server::ip_discovery(const endpoint_data& endpoint)
|
||||
{
|
||||
const uint32_t ip = 0x0100007f;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.write_ubyte(31); // type
|
||||
buffer.write_ubyte(2); // version
|
||||
buffer.write_ubyte(0); // version
|
||||
buffer.write_uint32(ip); // external ip
|
||||
buffer.write_uint16(3074); // port
|
||||
|
||||
this->send(endpoint, buffer.get_buffer());
|
||||
}
|
||||
|
||||
void stun_server::nat_discovery(const endpoint_data& endpoint)
|
||||
{
|
||||
const uint32_t ip = 0x0100007f;
|
||||
|
||||
byte_buffer buffer;
|
||||
buffer.set_use_data_types(false);
|
||||
buffer.write_ubyte(21); // type
|
||||
buffer.write_ubyte(2); // version
|
||||
buffer.write_ubyte(0); // version
|
||||
buffer.write_uint32(ip); // external ip
|
||||
buffer.write_uint16(3074); // port
|
||||
buffer.write_uint32(this->get_address()); // server ip
|
||||
buffer.write_uint16(3074); // server port
|
||||
|
||||
this->send(endpoint, buffer.get_buffer());
|
||||
}
|
||||
}
|
18
source/proxy-dll/demonware/servers/stun_server.hpp
Normal file
18
source/proxy-dll/demonware/servers/stun_server.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "udp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class stun_server : public udp_server
|
||||
{
|
||||
public:
|
||||
using udp_server::udp_server;
|
||||
|
||||
private:
|
||||
void handle(const endpoint_data& endpoint, const std::string& packet) override;
|
||||
|
||||
void ip_discovery(const endpoint_data& endpoint);
|
||||
void nat_discovery(const endpoint_data& endpoint);
|
||||
};
|
||||
}
|
84
source/proxy-dll/demonware/servers/tcp_server.cpp
Normal file
84
source/proxy-dll/demonware/servers/tcp_server.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include <std_include.hpp>
|
||||
#include "tcp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void tcp_server::handle_input(const char* buf, size_t size)
|
||||
{
|
||||
in_queue_.access([&](data_queue& queue)
|
||||
{
|
||||
queue.emplace(buf, size);
|
||||
});
|
||||
}
|
||||
|
||||
size_t tcp_server::handle_output(char* buf, size_t size)
|
||||
{
|
||||
if (out_queue_.get_raw().empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return out_queue_.access<size_t>([&](stream_queue& queue)
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
buf[i] = queue.front();
|
||||
queue.pop();
|
||||
}
|
||||
|
||||
return size;
|
||||
});
|
||||
}
|
||||
|
||||
bool tcp_server::pending_data()
|
||||
{
|
||||
return !this->out_queue_.get_raw().empty();
|
||||
}
|
||||
|
||||
void tcp_server::frame()
|
||||
{
|
||||
if (this->in_queue_.get_raw().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::string packet{};
|
||||
const auto result = this->in_queue_.access<bool>([&](data_queue& queue)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
packet = std::move(queue.front());
|
||||
queue.pop();
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->handle(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void tcp_server::send(const std::string& data)
|
||||
{
|
||||
out_queue_.access([&](stream_queue& queue)
|
||||
{
|
||||
for (const auto& val : data)
|
||||
{
|
||||
queue.push(val);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
27
source/proxy-dll/demonware/servers/tcp_server.hpp
Normal file
27
source/proxy-dll/demonware/servers/tcp_server.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class tcp_server : public base_server
|
||||
{
|
||||
public:
|
||||
using base_server::base_server;
|
||||
|
||||
void handle_input(const char* buf, size_t size);
|
||||
size_t handle_output(char* buf, size_t size);
|
||||
bool pending_data();
|
||||
void frame() override;
|
||||
|
||||
protected:
|
||||
virtual void handle(const std::string& data) = 0;
|
||||
|
||||
void send(const std::string& data);
|
||||
|
||||
private:
|
||||
utils::concurrency::container<data_queue> in_queue_;
|
||||
utils::concurrency::container<stream_queue> out_queue_;
|
||||
};
|
||||
}
|
103
source/proxy-dll/demonware/servers/udp_server.cpp
Normal file
103
source/proxy-dll/demonware/servers/udp_server.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <std_include.hpp>
|
||||
#include "udp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void udp_server::handle_input(const char* buf, size_t size, endpoint_data endpoint)
|
||||
{
|
||||
in_queue_.access([&](in_queue& queue)
|
||||
{
|
||||
in_packet p;
|
||||
p.data = std::string{buf, size};
|
||||
p.endpoint = std::move(endpoint);
|
||||
|
||||
queue.emplace(std::move(p));
|
||||
});
|
||||
}
|
||||
|
||||
size_t udp_server::handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen)
|
||||
{
|
||||
return out_queue_.access<size_t>([&](socket_queue_map& map) -> size_t
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& queue = entry->second;
|
||||
|
||||
if (queue.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto data = std::move(queue.front());
|
||||
queue.pop();
|
||||
|
||||
const auto copy_size = std::min(size, data.data.size());
|
||||
std::memcpy(buf, data.data.data(), copy_size);
|
||||
std::memcpy(address, &data.address, sizeof(data.address));
|
||||
*addrlen = sizeof(data.address);
|
||||
|
||||
return copy_size;
|
||||
});
|
||||
}
|
||||
|
||||
bool udp_server::pending_data(SOCKET socket)
|
||||
{
|
||||
return this->out_queue_.access<bool>([&](const socket_queue_map& map)
|
||||
{
|
||||
const auto entry = map.find(socket);
|
||||
if (entry == map.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !entry->second.empty();
|
||||
});
|
||||
}
|
||||
|
||||
void udp_server::send(const endpoint_data& endpoint, std::string data)
|
||||
{
|
||||
out_queue_.access([&](socket_queue_map& map)
|
||||
{
|
||||
out_packet p;
|
||||
p.data = std::move(data);
|
||||
p.address = endpoint.address;
|
||||
|
||||
map[endpoint.socket].emplace(std::move(p));
|
||||
});
|
||||
}
|
||||
|
||||
void udp_server::frame()
|
||||
{
|
||||
if (this->in_queue_.get_raw().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
in_packet packet{};
|
||||
const auto result = this->in_queue_.access<bool>([&](in_queue& queue)
|
||||
{
|
||||
if (queue.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
packet = std::move(queue.front());
|
||||
queue.pop();
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
this->handle(packet.endpoint, std::move(packet.data));
|
||||
}
|
||||
}
|
||||
}
|
62
source/proxy-dll/demonware/servers/udp_server.hpp
Normal file
62
source/proxy-dll/demonware/servers/udp_server.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class udp_server : public base_server
|
||||
{
|
||||
public:
|
||||
struct endpoint_data
|
||||
{
|
||||
SOCKET socket{};
|
||||
sockaddr_in address{};
|
||||
|
||||
endpoint_data() = default;
|
||||
|
||||
endpoint_data(const SOCKET sock, const sockaddr* addr, const int size)
|
||||
{
|
||||
if (size != sizeof(this->address))
|
||||
{
|
||||
throw std::runtime_error("Invalid size");
|
||||
}
|
||||
|
||||
this->socket = sock;
|
||||
std::memcpy(&this->address, addr, sizeof(this->address));
|
||||
}
|
||||
};
|
||||
|
||||
using base_server::base_server;
|
||||
|
||||
void handle_input(const char* buf, size_t size, endpoint_data endpoint);
|
||||
size_t handle_output(SOCKET socket, char* buf, size_t size, sockaddr* address, int* addrlen);
|
||||
bool pending_data(SOCKET socket);
|
||||
|
||||
void frame() override;
|
||||
|
||||
protected:
|
||||
virtual void handle(const endpoint_data& endpoint, const std::string& data) = 0;
|
||||
void send(const endpoint_data& endpoint, std::string data);
|
||||
|
||||
private:
|
||||
struct in_packet
|
||||
{
|
||||
std::string data;
|
||||
endpoint_data endpoint;
|
||||
};
|
||||
|
||||
struct out_packet
|
||||
{
|
||||
std::string data;
|
||||
sockaddr_in address;
|
||||
};
|
||||
|
||||
using in_queue = std::queue<in_packet>;
|
||||
using out_queue = std::queue<out_packet>;
|
||||
using socket_queue_map = std::unordered_map<SOCKET, out_queue>;
|
||||
|
||||
utils::concurrency::container<in_queue> in_queue_;
|
||||
utils::concurrency::container<socket_queue_map> out_queue_;
|
||||
};
|
||||
}
|
11
source/proxy-dll/demonware/servers/umbrella_server.cpp
Normal file
11
source/proxy-dll/demonware/servers/umbrella_server.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "umbrella_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
void umbrella_server::handle(const std::string& packet)
|
||||
{
|
||||
// TODO:
|
||||
}
|
||||
}
|
14
source/proxy-dll/demonware/servers/umbrella_server.hpp
Normal file
14
source/proxy-dll/demonware/servers/umbrella_server.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "tcp_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class umbrella_server : public tcp_server
|
||||
{
|
||||
public:
|
||||
using tcp_server::tcp_server;
|
||||
|
||||
private:
|
||||
void handle(const std::string& packet) override;
|
||||
};
|
||||
}
|
89
source/proxy-dll/demonware/service.hpp
Normal file
89
source/proxy-dll/demonware/service.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include <utils/string.hpp>
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class service
|
||||
{
|
||||
using callback_t = std::function<void(service_server*, byte_buffer*)>;
|
||||
|
||||
uint8_t id_;
|
||||
std::string name_;
|
||||
std::mutex mutex_;
|
||||
uint8_t task_id_;
|
||||
std::map<uint8_t, callback_t> tasks_;
|
||||
|
||||
public:
|
||||
virtual ~service() = default;
|
||||
service(service&&) = delete;
|
||||
service(const service&) = delete;
|
||||
service& operator=(const service&) = delete;
|
||||
|
||||
service(const uint8_t id, std::string name) : id_(id), name_(std::move(name)), task_id_(0)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t id() const
|
||||
{
|
||||
return this->id_;
|
||||
}
|
||||
|
||||
const std::string& name() const
|
||||
{
|
||||
return this->name_;
|
||||
}
|
||||
|
||||
uint8_t task_id() const
|
||||
{
|
||||
return this->task_id_;
|
||||
}
|
||||
|
||||
virtual void exec_task(service_server* server, const std::string& data)
|
||||
{
|
||||
std::lock_guard<std::mutex> _(this->mutex_);
|
||||
|
||||
byte_buffer buffer(data);
|
||||
|
||||
buffer.read_ubyte(&this->task_id_);
|
||||
|
||||
const auto& it = this->tasks_.find(this->task_id_);
|
||||
|
||||
if (it != this->tasks_.end())
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] %s: executing task '%d'", name_.data(), this->task_id_);
|
||||
#endif
|
||||
|
||||
it->second(server, &buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[DW] %s: missing task '%d'", name_.data(), this->task_id_);
|
||||
|
||||
// return no error
|
||||
server->create_reply(this->task_id_)->send();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
template <typename Class, typename T, typename... Args>
|
||||
void register_task(const uint8_t id, T (Class::* callback)(Args ...) const)
|
||||
{
|
||||
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||
{
|
||||
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Class, typename T, typename... Args>
|
||||
void register_task(const uint8_t id, T (Class::* callback)(Args ...))
|
||||
{
|
||||
this->tasks_[id] = [this, callback](Args ... args) -> T
|
||||
{
|
||||
return (reinterpret_cast<Class*>(this)->*callback)(args...);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
28
source/proxy-dll/demonware/services.hpp
Normal file
28
source/proxy-dll/demonware/services.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "bit_buffer.hpp"
|
||||
#include "byte_buffer.hpp"
|
||||
#include "data_types.hpp"
|
||||
#include "reply.hpp"
|
||||
#include "service.hpp"
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
#include "services/bdStats.hpp" // 4 [ UNKNOWN ]
|
||||
#include "services/bdProfiles.hpp" // 8
|
||||
#include "services/bdTitleUtilities.hpp" // 12 [ ESSENTIAL ]
|
||||
#include "services/bdKeyArchive.hpp" // 15 [ USELESS ]
|
||||
#include "services/bdBandwidthTest.hpp" // 18
|
||||
#include "services/bdCounter.hpp" // 23
|
||||
#include "services/bdDML.hpp" // 27 [ ESSENTIAL ]
|
||||
#include "services/bdGroup.hpp" // 28 [ USELESS ]
|
||||
#include "services/bdAnticheat.hpp" // 38 [ UNKNOWN ]
|
||||
#include "services/bdTags.hpp" // 52
|
||||
#include "services/bdPooledStorage.hpp" // 58
|
||||
#include "services/bdEventLog.hpp" // 67
|
||||
#include "services/bdRichPresence.hpp" // 68
|
||||
#include "services/bdMarketplace.hpp" // 80
|
||||
#include "services/bdPublisherVariables.hpp"// 95
|
||||
#include "services/bdMarketingComms.hpp" // 104
|
||||
#include "services/bdUNK125.hpp" // 125 [ PATCHED OUT ]
|
||||
#include "services/bdObjectStore.hpp" // 193 [ ESSENTIAL ]
|
||||
#include "services/bdLootGeneration.hpp" // 195 [ UNKNOWN ]
|
49
source/proxy-dll/demonware/services/bdAnticheat.cpp
Normal file
49
source/proxy-dll/demonware/services/bdAnticheat.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdAnticheat::bdAnticheat() : service(38, "bdAnticheat")
|
||||
{
|
||||
this->register_task(2, &bdAnticheat::answerChallenges);
|
||||
this->register_task(3, &bdAnticheat::reportConsoleID);
|
||||
this->register_task(4, &bdAnticheat::reportConsoleDetails);
|
||||
this->register_task(5, &bdAnticheat::answerTOTPChallenge);
|
||||
this->register_task(6, &bdAnticheat::reportExtendedAuthInfo);
|
||||
}
|
||||
|
||||
void bdAnticheat::answerChallenges(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdAnticheat::reportConsoleID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdAnticheat::reportConsoleDetails(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdAnticheat::answerTOTPChallenge(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdAnticheat::reportExtendedAuthInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO: Read data as soon as needed
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
17
source/proxy-dll/demonware/services/bdAnticheat.hpp
Normal file
17
source/proxy-dll/demonware/services/bdAnticheat.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdAnticheat final : public service
|
||||
{
|
||||
public:
|
||||
bdAnticheat();
|
||||
|
||||
private:
|
||||
void answerChallenges(service_server* server, byte_buffer* buffer) const;
|
||||
void reportConsoleID(service_server* server, byte_buffer* buffer) const;
|
||||
void reportConsoleDetails(service_server* server, byte_buffer* buffer) const;
|
||||
void answerTOTPChallenge(service_server* server, byte_buffer* buffer) const;
|
||||
void reportExtendedAuthInfo(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
27
source/proxy-dll/demonware/services/bdBandwidthTest.cpp
Normal file
27
source/proxy-dll/demonware/services/bdBandwidthTest.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
static uint8_t bandwidth_iw6[51] =
|
||||
{
|
||||
0x0F, 0xC1, 0x1C, 0x37, 0xB8, 0xEF, 0x7C, 0xD6, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xF4, 0x01, 0x00, 0x00, 0xD0, 0x07,
|
||||
0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x88, 0x13, 0x00, 0x00, 0xF4, 0x01,
|
||||
0x00, 0x00, 0x02, 0x0C, 0x88, 0xB3, 0x04, 0x65, 0x89, 0xBF, 0xC3, 0x6A,
|
||||
0x27, 0x94, 0xD4, 0x8F
|
||||
};
|
||||
|
||||
bdBandwidthTest::bdBandwidthTest() : service(18, "bdBandwidthTest")
|
||||
{
|
||||
}
|
||||
|
||||
void bdBandwidthTest::exec_task(service_server* server, const std::string& data)
|
||||
{
|
||||
byte_buffer buffer;
|
||||
buffer.write(sizeof bandwidth_iw6, bandwidth_iw6);
|
||||
|
||||
auto reply = server->create_message(5);
|
||||
reply->send(&buffer, true);
|
||||
}
|
||||
}
|
13
source/proxy-dll/demonware/services/bdBandwidthTest.hpp
Normal file
13
source/proxy-dll/demonware/services/bdBandwidthTest.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdBandwidthTest final : public service
|
||||
{
|
||||
public:
|
||||
bdBandwidthTest();
|
||||
|
||||
private:
|
||||
void exec_task(service_server* server, const std::string& data) override;
|
||||
};
|
||||
}
|
25
source/proxy-dll/demonware/services/bdCounter.cpp
Normal file
25
source/proxy-dll/demonware/services/bdCounter.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdCounter::bdCounter() : service(23, "bdCounter")
|
||||
{
|
||||
this->register_task(1, &bdCounter::incrementCounters);
|
||||
this->register_task(2, &bdCounter::getCounterTotals);
|
||||
}
|
||||
|
||||
void bdCounter::incrementCounters(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdCounter::getCounterTotals(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
source/proxy-dll/demonware/services/bdCounter.hpp
Normal file
14
source/proxy-dll/demonware/services/bdCounter.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdCounter final : public service
|
||||
{
|
||||
public:
|
||||
bdCounter();
|
||||
|
||||
private:
|
||||
void incrementCounters(service_server* server, byte_buffer* buffer) const;
|
||||
void getCounterTotals(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
37
source/proxy-dll/demonware/services/bdDML.cpp
Normal file
37
source/proxy-dll/demonware/services/bdDML.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdDML::bdDML() : service(27, "bdDML")
|
||||
{
|
||||
this->register_task(3, &bdDML::getUserHierarchicalData);
|
||||
}
|
||||
|
||||
void bdDML::getUserHierarchicalData(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
auto result = new bdDMLHierarchicalInfo;
|
||||
result->country_code = "US";
|
||||
result->country = "United States";
|
||||
result->region = "New York";
|
||||
result->city = "New York";
|
||||
result->latitude = 0;
|
||||
result->longitude = 0;
|
||||
|
||||
result->asn = 0x2119;
|
||||
result->timezone = "+01:00";
|
||||
|
||||
result->m_tier0 = 0;
|
||||
result->m_tier1 = 0;
|
||||
result->m_tier2 = 0;
|
||||
result->m_tier3 = 0;
|
||||
result->m_confidence = 0;
|
||||
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(result);
|
||||
reply->send();
|
||||
}
|
||||
}
|
16
source/proxy-dll/demonware/services/bdDML.hpp
Normal file
16
source/proxy-dll/demonware/services/bdDML.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdDML final : public service
|
||||
{
|
||||
public:
|
||||
bdDML();
|
||||
|
||||
private:
|
||||
void recordIP(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserData(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserHierarchicalData(service_server* server, byte_buffer* buffer) const;
|
||||
void getUsersLastLogonData(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
57
source/proxy-dll/demonware/services/bdEventLog.cpp
Normal file
57
source/proxy-dll/demonware/services/bdEventLog.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdEventLog::bdEventLog() : service(67, "bdEventLog")
|
||||
{
|
||||
this->register_task(1, &bdEventLog::recordEvent);
|
||||
this->register_task(2, &bdEventLog::recordEventBin);
|
||||
this->register_task(3, &bdEventLog::recordEvents);
|
||||
this->register_task(4, &bdEventLog::recordEventsBin);
|
||||
this->register_task(5, &bdEventLog::recordEventsMixed);
|
||||
this->register_task(6, &bdEventLog::initializeFiltering);
|
||||
}
|
||||
|
||||
void bdEventLog::recordEvent(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdEventLog::recordEventBin(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdEventLog::recordEvents(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdEventLog::recordEventsBin(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdEventLog::recordEventsMixed(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdEventLog::initializeFiltering(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
18
source/proxy-dll/demonware/services/bdEventLog.hpp
Normal file
18
source/proxy-dll/demonware/services/bdEventLog.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdEventLog final : public service
|
||||
{
|
||||
public:
|
||||
bdEventLog();
|
||||
|
||||
private:
|
||||
void recordEvent(service_server* server, byte_buffer* buffer) const;
|
||||
void recordEventBin(service_server* server, byte_buffer* buffer) const;
|
||||
void recordEvents(service_server* server, byte_buffer* buffer) const;
|
||||
void recordEventsBin(service_server* server, byte_buffer* buffer) const;
|
||||
void recordEventsMixed(service_server* server, byte_buffer* buffer) const;
|
||||
void initializeFiltering(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
41
source/proxy-dll/demonware/services/bdGroup.cpp
Normal file
41
source/proxy-dll/demonware/services/bdGroup.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdGroup::bdGroup() : service(28, "bdGroup")
|
||||
{
|
||||
this->register_task(1, &bdGroup::setGroups);
|
||||
this->register_task(2, &bdGroup::setGroupsForEntity);
|
||||
this->register_task(3, &bdGroup::getEntityGroups);
|
||||
this->register_task(4, &bdGroup::getGroupCounts);
|
||||
}
|
||||
|
||||
void bdGroup::setGroups(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdGroup::setGroupsForEntity(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdGroup::getEntityGroups(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdGroup::getGroupCounts(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
16
source/proxy-dll/demonware/services/bdGroup.hpp
Normal file
16
source/proxy-dll/demonware/services/bdGroup.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdGroup final : public service
|
||||
{
|
||||
public:
|
||||
bdGroup();
|
||||
|
||||
private:
|
||||
void setGroups(service_server* server, byte_buffer* buffer) const;
|
||||
void setGroupsForEntity(service_server* server, byte_buffer* buffer) const;
|
||||
void getEntityGroups(service_server* server, byte_buffer* buffer) const;
|
||||
void getGroupCounts(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
48
source/proxy-dll/demonware/services/bdKeyArchive.cpp
Normal file
48
source/proxy-dll/demonware/services/bdKeyArchive.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdKeyArchive::bdKeyArchive() : service(15, "bdKeyArchive")
|
||||
{
|
||||
this->register_task(1, &bdKeyArchive::write);
|
||||
this->register_task(2, &bdKeyArchive::read);
|
||||
this->register_task(3, &bdKeyArchive::readAll);
|
||||
this->register_task(5, &bdKeyArchive::readMultipleEntityIDs);
|
||||
this->register_task(6, &bdKeyArchive::writeMultipleEntityIDs);
|
||||
}
|
||||
|
||||
void bdKeyArchive::write(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdKeyArchive::read(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdKeyArchive::readAll(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdKeyArchive::readMultipleEntityIDs(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
void bdKeyArchive::writeMultipleEntityIDs(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
17
source/proxy-dll/demonware/services/bdKeyArchive.hpp
Normal file
17
source/proxy-dll/demonware/services/bdKeyArchive.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdKeyArchive final : public service
|
||||
{
|
||||
public:
|
||||
bdKeyArchive();
|
||||
|
||||
private:
|
||||
void write(service_server* server, byte_buffer* buffer) const;
|
||||
void read(service_server* server, byte_buffer* buffer) const;
|
||||
void readAll(service_server* server, byte_buffer* buffer) const;
|
||||
void readMultipleEntityIDs(service_server* server, byte_buffer* buffer) const;
|
||||
void writeMultipleEntityIDs(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
source/proxy-dll/demonware/services/bdLootGeneration.cpp
Normal file
17
source/proxy-dll/demonware/services/bdLootGeneration.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdLootGeneration::bdLootGeneration() : service(195, "bdLootGeneration")
|
||||
{
|
||||
this->register_task(2, &bdLootGeneration::getPlayerState);
|
||||
}
|
||||
|
||||
void bdLootGeneration::getPlayerState(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(""); // Un-handled
|
||||
}
|
||||
}
|
13
source/proxy-dll/demonware/services/bdLootGeneration.hpp
Normal file
13
source/proxy-dll/demonware/services/bdLootGeneration.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdLootGeneration final : public service
|
||||
{
|
||||
public:
|
||||
bdLootGeneration();
|
||||
|
||||
private:
|
||||
void getPlayerState(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
source/proxy-dll/demonware/services/bdMarketingComms.cpp
Normal file
25
source/proxy-dll/demonware/services/bdMarketingComms.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMarketingComms::bdMarketingComms() : service(104, "bdMarketingComms")
|
||||
{
|
||||
this->register_task(6, &bdMarketingComms::getMessages);
|
||||
this->register_task(7, &bdMarketingComms::reportMessagesViewed);
|
||||
}
|
||||
|
||||
void bdMarketingComms::getMessages(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMarketingComms::reportMessagesViewed(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
source/proxy-dll/demonware/services/bdMarketingComms.hpp
Normal file
14
source/proxy-dll/demonware/services/bdMarketingComms.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdMarketingComms final : public service
|
||||
{
|
||||
public:
|
||||
bdMarketingComms();
|
||||
|
||||
private:
|
||||
void getMessages(service_server* server, byte_buffer* buffer) const;
|
||||
void reportMessagesViewed(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
26
source/proxy-dll/demonware/services/bdMarketplace.cpp
Normal file
26
source/proxy-dll/demonware/services/bdMarketplace.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMarketplace::bdMarketplace() : service(80, "bdMarketplace")
|
||||
{
|
||||
this->register_task(204, &bdMarketplace::getInventoryPaginated);
|
||||
this->register_task(245, &bdMarketplace::getBalancesV3);
|
||||
}
|
||||
|
||||
void bdMarketplace::getInventoryPaginated(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdMarketplace::getBalancesV3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send("");
|
||||
}
|
||||
}
|
14
source/proxy-dll/demonware/services/bdMarketplace.hpp
Normal file
14
source/proxy-dll/demonware/services/bdMarketplace.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdMarketplace final : public service
|
||||
{
|
||||
public:
|
||||
bdMarketplace();
|
||||
|
||||
private:
|
||||
void getInventoryPaginated(service_server* server, byte_buffer* buffer) const;
|
||||
void getBalancesV3(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
168
source/proxy-dll/demonware/services/bdObjectStore.cpp
Normal file
168
source/proxy-dll/demonware/services/bdObjectStore.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
#include <picoproto.h>
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include "../objects.hpp"
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <component/platform.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdObjectStore::bdObjectStore() : service(193, "bdObjectStore")
|
||||
{
|
||||
this->register_task(3, &bdObjectStore::listUserObjects);
|
||||
this->register_task(18, &bdObjectStore::getUserObjectCounts);
|
||||
|
||||
this->register_task(8, &bdObjectStore::getPublisherObject);
|
||||
this->register_task(9, &bdObjectStore::listPublisherObjectsByCategory);
|
||||
|
||||
this->register_task(6, &bdObjectStore::getUserObjectsVectorized);
|
||||
this->register_task(2, &bdObjectStore::uploadUserObject);
|
||||
this->register_task(5, &bdObjectStore::getUserObject); // Un-handled; Not used by engine at all
|
||||
this->register_task(7, &bdObjectStore::uploadUserObjectsVectorized);
|
||||
|
||||
this->register_task(16, &bdObjectStore::getPublisherObjectMetadatas); // Un-handled; Not needed if user already has LPC
|
||||
}
|
||||
|
||||
void bdObjectStore::getUserObject(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
auto reply = server->create_reply(this->task_id(), 20000/*BD_OBJECTSTORE_PROXY_OBJECT_NOT_FOUND*/);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdObjectStore::getPublisherObject(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
auto reply = server->create_reply(this->task_id(), 20000/*BD_OBJECTSTORE_PROXY_OBJECT_NOT_FOUND*/);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdObjectStore::listUserObjects(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string response_json = generate_user_objects_list_json();
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
|
||||
void bdObjectStore::getUserObjectCounts(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string response_json = generate_user_objects_count_json();
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
|
||||
void bdObjectStore::listPublisherObjectsByCategory(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string response_json = generate_publisher_objects_list_json("");
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
|
||||
void bdObjectStore::getUserObjectsVectorized(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string structed_data;
|
||||
buffer->read_struct(&structed_data);
|
||||
|
||||
picoproto::Message request_buffer;
|
||||
request_buffer.ParseFromBytes(reinterpret_cast<uint8_t*>(structed_data.data()), structed_data.size());
|
||||
|
||||
std::string str4 = request_buffer.GetString(4);
|
||||
picoproto::Message nested_buffer;
|
||||
nested_buffer.ParseFromBytes(reinterpret_cast<uint8_t*>(str4.data()), str4.size());
|
||||
|
||||
std::vector<objectID> requested_objects_list;
|
||||
|
||||
rapidjson::Document requested_objects_list_json;
|
||||
requested_objects_list_json.Parse(nested_buffer.GetString(2));
|
||||
for (rapidjson::SizeType i = 0; i < requested_objects_list_json.Size(); i++) {
|
||||
requested_objects_list.push_back({ std::format("bnet-{}", platform::bnet_get_userid())/*requested_objects_list_json[i]["owner"].GetString()*/, requested_objects_list_json[i]["name"].GetString() });
|
||||
}
|
||||
|
||||
std::string response_json = deliver_user_objects_vectorized_json(requested_objects_list);
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
|
||||
void bdObjectStore::getPublisherObjectMetadatas(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(""); // Un-handled
|
||||
}
|
||||
|
||||
void bdObjectStore::uploadUserObject(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string structed_data;
|
||||
buffer->read_struct(&structed_data);
|
||||
|
||||
picoproto::Message request_buffer;
|
||||
request_buffer.ParseFromBytes(reinterpret_cast<uint8_t*>(structed_data.data()), structed_data.size());
|
||||
|
||||
std::string request = request_buffer.GetString(1);
|
||||
std::string url = request_buffer.GetString(2);
|
||||
std::string data = request_buffer.GetString(3);
|
||||
|
||||
std::string file = utils::string::split(url, '/')[8];
|
||||
std::string path = get_user_file_path(file);
|
||||
|
||||
if (!utils::io::write_file(path, data))
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[bdObjectStore::uploadUserObject] error on writing '%s'", file.data());
|
||||
else
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[bdObjectStore::uploadUserObject] saved user file '%s'", file.data());
|
||||
|
||||
std::string response_json = construct_file_upload_result_json(file);
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
|
||||
void bdObjectStore::uploadUserObjectsVectorized(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string structed_data;
|
||||
buffer->read_struct(&structed_data);
|
||||
|
||||
picoproto::Message request_buffer;
|
||||
request_buffer.ParseFromBytes(reinterpret_cast<uint8_t*>(structed_data.data()), structed_data.size());
|
||||
|
||||
std::string request = request_buffer.GetString(1);
|
||||
std::string payload = request_buffer.GetString(3);
|
||||
|
||||
rapidjson::Document vectorized_upload_json;
|
||||
vectorized_upload_json.Parse(payload.data());
|
||||
|
||||
std::vector<std::string> uploaded_objects_list;
|
||||
|
||||
const rapidjson::Value& objects = vectorized_upload_json["objects"];
|
||||
for (rapidjson::SizeType i = 0; i < objects.Size(); i++) // Uses SizeType instead of size_t
|
||||
{
|
||||
const rapidjson::Value& content = objects[i]["content"];
|
||||
const rapidjson::Value& name = objects[i]["metadata"]["name"];
|
||||
const rapidjson::Value& checksum = objects[i]["metadata"]["checksum"];
|
||||
|
||||
std::string data = utils::cryptography::base64::decode(content.GetString());
|
||||
const auto path = std::format("{}/{}", platform::get_userdata_directory(), name.GetString());
|
||||
|
||||
uploaded_objects_list.push_back(name.GetString());
|
||||
|
||||
if (!utils::io::write_file(path, data))
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[bdObjectStore::uploadUserObjectsVectorized] error on writing '%s'", name.GetString());
|
||||
else
|
||||
logger::write(logger::LOG_TYPE_DEBUG, "[bdObjectStore::uploadUserObjectsVectorized] saved user file '%s'", name.GetString());
|
||||
}
|
||||
|
||||
std::string response_json = construct_vectorized_upload_list_json(uploaded_objects_list);
|
||||
std::string response_buff = serialize_objectstore_structed_buffer(response_json);
|
||||
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send(response_buff);
|
||||
}
|
||||
}
|
||||
|
21
source/proxy-dll/demonware/services/bdObjectStore.hpp
Normal file
21
source/proxy-dll/demonware/services/bdObjectStore.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdObjectStore final : public service
|
||||
{
|
||||
public:
|
||||
bdObjectStore();
|
||||
|
||||
private:
|
||||
void getUserObject(service_server* server, byte_buffer* buffer) const;
|
||||
void getPublisherObject(service_server* server, byte_buffer* buffer) const;
|
||||
void listUserObjects(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserObjectCounts(service_server* server, byte_buffer* buffer) const;
|
||||
void listPublisherObjectsByCategory(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserObjectsVectorized(service_server* server, byte_buffer* buffer) const;
|
||||
void getPublisherObjectMetadatas(service_server* server, byte_buffer* buffer) const;
|
||||
void uploadUserObject(service_server* server, byte_buffer* buffer) const;
|
||||
void uploadUserObjectsVectorized(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
97
source/proxy-dll/demonware/services/bdPooledStorage.cpp
Normal file
97
source/proxy-dll/demonware/services/bdPooledStorage.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdPooledStorage::bdPooledStorage() : service(58, "bdPooledStorage")
|
||||
{
|
||||
this->register_task(1, &bdPooledStorage::getPooledMetaDataByID);
|
||||
this->register_task(5, &bdPooledStorage::_preUpload);
|
||||
this->register_task(6, &bdPooledStorage::_postUploadFile);
|
||||
this->register_task(8, &bdPooledStorage::remove);
|
||||
this->register_task(9, &bdPooledStorage::_preDownload);
|
||||
this->register_task(17, &bdPooledStorage::_preUploadSummary);
|
||||
this->register_task(18, &bdPooledStorage::_postUploadSummary);
|
||||
this->register_task(19, &bdPooledStorage::_preDownloadSummary);
|
||||
this->register_task(20, &bdPooledStorage::_preUploadMultiPart);
|
||||
this->register_task(21, &bdPooledStorage::_postUploadMultiPart);
|
||||
this->register_task(22, &bdPooledStorage::_preDownloadMultiPart);
|
||||
}
|
||||
|
||||
void bdPooledStorage::getPooledMetaDataByID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preUpload(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_postUploadFile(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::remove(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preDownload(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preUploadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_postUploadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preDownloadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preUploadMultiPart(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_postUploadMultiPart(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdPooledStorage::_preDownloadMultiPart(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
23
source/proxy-dll/demonware/services/bdPooledStorage.hpp
Normal file
23
source/proxy-dll/demonware/services/bdPooledStorage.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdPooledStorage final : public service
|
||||
{
|
||||
public:
|
||||
bdPooledStorage();
|
||||
|
||||
private:
|
||||
void getPooledMetaDataByID(service_server* server, byte_buffer* buffer) const;
|
||||
void _preUpload(service_server* server, byte_buffer* buffer) const;
|
||||
void _postUploadFile(service_server* server, byte_buffer* buffer) const;
|
||||
void remove(service_server* server, byte_buffer* buffer) const;
|
||||
void _preDownload(service_server* server, byte_buffer* buffer) const;
|
||||
void _preUploadSummary(service_server* server, byte_buffer* buffer) const;
|
||||
void _postUploadSummary(service_server* server, byte_buffer* buffer) const;
|
||||
void _preDownloadSummary(service_server* server, byte_buffer* buffer) const;
|
||||
void _preUploadMultiPart(service_server* server, byte_buffer* buffer) const;
|
||||
void _postUploadMultiPart(service_server* server, byte_buffer* buffer) const;
|
||||
void _preDownloadMultiPart(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
95
source/proxy-dll/demonware/services/bdProfiles.cpp
Normal file
95
source/proxy-dll/demonware/services/bdProfiles.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
#include <utils/io.hpp>
|
||||
#include <component/platform.hpp>
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdProfiles::bdProfiles() : service(8, "bdProfiles")
|
||||
{
|
||||
this->register_task(1, &bdProfiles::getPublicInfos);
|
||||
this->register_task(2, &bdProfiles::getPrivateInfo);
|
||||
this->register_task(3, &bdProfiles::setPublicInfo);
|
||||
this->register_task(4, &bdProfiles::setPrivateInfo);
|
||||
this->register_task(5, &bdProfiles::deleteProfile);
|
||||
this->register_task(6, &bdProfiles::setPrivateInfoByUserID);
|
||||
this->register_task(7, &bdProfiles::getPrivateInfoByUserID);
|
||||
this->register_task(8, &bdProfiles::setPublicInfoByUserID);
|
||||
}
|
||||
|
||||
void bdProfiles::getPublicInfos(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
uint64_t entity_id;
|
||||
buffer->read_uint64(&entity_id);
|
||||
|
||||
auto* result = new bdPublicProfileInfo;
|
||||
result->m_entityID = entity_id;
|
||||
result->m_VERSION = 4;
|
||||
|
||||
if (utils::io::read_file(std::format("{}/profileInfo_{}", platform::get_userdata_directory(), entity_id), &result->m_ddl))
|
||||
{
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(result);
|
||||
reply->send();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto reply = server->create_reply(this->task_id(), 800/*BD_NO_PROFILE_INFO_EXISTS*/);
|
||||
reply->send();
|
||||
}
|
||||
}
|
||||
|
||||
void bdProfiles::setPublicInfo(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
int32_t version; std::string ddl;
|
||||
buffer->read_int32(&version);
|
||||
buffer->read_blob(&ddl);
|
||||
|
||||
utils::io::write_file(std::format("{}/profileInfo_{}", platform::get_userdata_directory(), platform::bnet_get_userid()), ddl);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::getPrivateInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::setPrivateInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::deleteProfile(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::setPrivateInfoByUserID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::getPrivateInfoByUserID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdProfiles::setPublicInfoByUserID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
20
source/proxy-dll/demonware/services/bdProfiles.hpp
Normal file
20
source/proxy-dll/demonware/services/bdProfiles.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdProfiles final : public service
|
||||
{
|
||||
public:
|
||||
bdProfiles();
|
||||
|
||||
private:
|
||||
void getPublicInfos(service_server* server, byte_buffer* buffer) const;
|
||||
void getPrivateInfo(service_server* server, byte_buffer* buffer) const;
|
||||
void setPublicInfo(service_server* server, byte_buffer* buffer) const;
|
||||
void setPrivateInfo(service_server* server, byte_buffer* buffer) const;
|
||||
void deleteProfile(service_server* server, byte_buffer* buffer) const;
|
||||
void setPrivateInfoByUserID(service_server* server, byte_buffer* buffer) const;
|
||||
void getPrivateInfoByUserID(service_server* server, byte_buffer* buffer) const;
|
||||
void setPublicInfoByUserID(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
17
source/proxy-dll/demonware/services/bdPublisherVariables.cpp
Normal file
17
source/proxy-dll/demonware/services/bdPublisherVariables.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdPublisherVariables::bdPublisherVariables() : service(95, "bdPublisherVariables")
|
||||
{
|
||||
this->register_task(1, &bdPublisherVariables::retrievePublisherVariables);
|
||||
}
|
||||
|
||||
void bdPublisherVariables::retrievePublisherVariables(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
13
source/proxy-dll/demonware/services/bdPublisherVariables.hpp
Normal file
13
source/proxy-dll/demonware/services/bdPublisherVariables.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdPublisherVariables final : public service
|
||||
{
|
||||
public:
|
||||
bdPublisherVariables();
|
||||
|
||||
private:
|
||||
void retrievePublisherVariables(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
25
source/proxy-dll/demonware/services/bdRichPresence.cpp
Normal file
25
source/proxy-dll/demonware/services/bdRichPresence.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdRichPresence::bdRichPresence() : service(68, "bdRichPresence")
|
||||
{
|
||||
this->register_task(1, &bdRichPresence::setInfo);
|
||||
this->register_task(2, &bdRichPresence::getInfo);
|
||||
}
|
||||
|
||||
void bdRichPresence::setInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdRichPresence::getInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
14
source/proxy-dll/demonware/services/bdRichPresence.hpp
Normal file
14
source/proxy-dll/demonware/services/bdRichPresence.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdRichPresence final : public service
|
||||
{
|
||||
public:
|
||||
bdRichPresence();
|
||||
|
||||
private:
|
||||
void setInfo(service_server* server, byte_buffer* buffer) const;
|
||||
void getInfo(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
113
source/proxy-dll/demonware/services/bdStats.cpp
Normal file
113
source/proxy-dll/demonware/services/bdStats.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdStats::bdStats() : service(4, "bdStats")
|
||||
{
|
||||
this->register_task(1, &bdStats::writeStats);
|
||||
this->register_task(2, &bdStats::deleteStats);
|
||||
this->register_task(3, &bdStats::readStatsByEntityID);
|
||||
this->register_task(4, &bdStats::readStatsByRank);
|
||||
this->register_task(5, &bdStats::readStatsByPivot);
|
||||
this->register_task(6, &bdStats::readStatsByRating);
|
||||
this->register_task(7, &bdStats::readStatsByMultipleRanks);
|
||||
this->register_task(8, &bdStats::readExternalTitleStats);
|
||||
this->register_task(10, &bdStats::readExternalTitleNamedStats);
|
||||
this->register_task(11, &bdStats::readStatsByLeaderboardIDsAndEntityIDs);
|
||||
this->register_task(12, &bdStats::readStatsByMultipleRatings);
|
||||
this->register_task(13, &bdStats::startTaskStatReadByEntityIDV2);
|
||||
//this->register_task(14, &bdStats::writeServerValidatedStats);
|
||||
}
|
||||
|
||||
void bdStats::writeStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::deleteStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByEntityID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByRank(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByPivot(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByRating(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByMultipleRanks(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readExternalTitleStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readExternalTitleNamedStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByLeaderboardIDsAndEntityIDs(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::readStatsByMultipleRatings(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::startTaskStatReadByEntityIDV2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdStats::writeServerValidatedStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
25
source/proxy-dll/demonware/services/bdStats.hpp
Normal file
25
source/proxy-dll/demonware/services/bdStats.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdStats final : public service
|
||||
{
|
||||
public:
|
||||
bdStats();
|
||||
|
||||
private:
|
||||
void writeStats(service_server* server, byte_buffer* buffer) const;
|
||||
void deleteStats(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByEntityID(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByRank(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByPivot(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByRating(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByMultipleRanks(service_server* server, byte_buffer* buffer) const;
|
||||
void readExternalTitleStats(service_server* server, byte_buffer* buffer) const;
|
||||
void readExternalTitleNamedStats(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByLeaderboardIDsAndEntityIDs(service_server* server, byte_buffer* buffer) const;
|
||||
void readStatsByMultipleRatings(service_server* server, byte_buffer* buffer) const;
|
||||
void startTaskStatReadByEntityIDV2(service_server* server, byte_buffer* buffer) const;
|
||||
void writeServerValidatedStats(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
49
source/proxy-dll/demonware/services/bdTags.cpp
Normal file
49
source/proxy-dll/demonware/services/bdTags.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdTags::bdTags() : service(52, "bdTags")
|
||||
{
|
||||
this->register_task(1, &bdTags::getTagsForEntityIDs);
|
||||
this->register_task(2, &bdTags::setTagsForEntityID);
|
||||
this->register_task(3, &bdTags::removeTagsForEntityID);
|
||||
this->register_task(4, &bdTags::removeAllTagsForEntityID);
|
||||
this->register_task(5, &bdTags::searchByTagsBase);
|
||||
}
|
||||
|
||||
void bdTags::getTagsForEntityIDs(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTags::setTagsForEntityID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTags::removeTagsForEntityID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTags::removeAllTagsForEntityID(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTags::searchByTagsBase(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
17
source/proxy-dll/demonware/services/bdTags.hpp
Normal file
17
source/proxy-dll/demonware/services/bdTags.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTags final : public service
|
||||
{
|
||||
public:
|
||||
bdTags();
|
||||
|
||||
private:
|
||||
void getTagsForEntityIDs(service_server* server, byte_buffer* buffer) const;
|
||||
void setTagsForEntityID(service_server* server, byte_buffer* buffer) const;
|
||||
void removeTagsForEntityID(service_server* server, byte_buffer* buffer) const;
|
||||
void removeAllTagsForEntityID(service_server* server, byte_buffer* buffer) const;
|
||||
void searchByTagsBase(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
68
source/proxy-dll/demonware/services/bdTitleUtilities.cpp
Normal file
68
source/proxy-dll/demonware/services/bdTitleUtilities.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdTitleUtilities::bdTitleUtilities() : service(12, "bdTitleUtilities")
|
||||
{
|
||||
this->register_task(1, &bdTitleUtilities::verifyString);
|
||||
this->register_task(2, &bdTitleUtilities::getTitleStats);
|
||||
this->register_task(6, &bdTitleUtilities::getServerTime);
|
||||
this->register_task(7, &bdTitleUtilities::areUsersOnline);
|
||||
this->register_task(8, &bdTitleUtilities::getMAC);
|
||||
this->register_task(9, &bdTitleUtilities::getUserNames);
|
||||
this->register_task(10, &bdTitleUtilities::getUserIDs);
|
||||
}
|
||||
|
||||
void bdTitleUtilities::getServerTime(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
auto* const time_result = new bdTimeStamp;
|
||||
time_result->unix_time = uint32_t(time(nullptr));
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->add(time_result);
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::verifyString(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::getTitleStats(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::areUsersOnline(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::getMAC(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::getUserNames(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
|
||||
void bdTitleUtilities::getUserIDs(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply->send();
|
||||
}
|
||||
}
|
19
source/proxy-dll/demonware/services/bdTitleUtilities.hpp
Normal file
19
source/proxy-dll/demonware/services/bdTitleUtilities.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdTitleUtilities final : public service
|
||||
{
|
||||
public:
|
||||
bdTitleUtilities();
|
||||
|
||||
private:
|
||||
void verifyString(service_server* server, byte_buffer* buffer) const;
|
||||
void getTitleStats(service_server* server, byte_buffer* buffer) const;
|
||||
void getServerTime(service_server* server, byte_buffer* buffer) const;
|
||||
void areUsersOnline(service_server* server, byte_buffer* buffer) const;
|
||||
void getMAC(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserNames(service_server* server, byte_buffer* buffer) const;
|
||||
void getUserIDs(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
41
source/proxy-dll/demonware/services/bdUNK125.cpp
Normal file
41
source/proxy-dll/demonware/services/bdUNK125.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../services.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdUNK125::bdUNK125() : service(125, "bdUNK125")
|
||||
{
|
||||
this->register_task(1, &bdUNK125::task_unk1);
|
||||
this->register_task(2, &bdUNK125::task_unk2);
|
||||
this->register_task(3, &bdUNK125::task_unk3);
|
||||
this->register_task(9, &bdUNK125::task_unk9);
|
||||
}
|
||||
|
||||
void bdUNK125::task_unk1(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send("");
|
||||
}
|
||||
|
||||
void bdUNK125::task_unk2(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send("");
|
||||
}
|
||||
|
||||
void bdUNK125::task_unk3(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send("");
|
||||
}
|
||||
|
||||
void bdUNK125::task_unk9(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_structed_reply(this->task_id());
|
||||
reply->send("");
|
||||
}
|
||||
}
|
16
source/proxy-dll/demonware/services/bdUNK125.hpp
Normal file
16
source/proxy-dll/demonware/services/bdUNK125.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
class bdUNK125 final : public service
|
||||
{
|
||||
public:
|
||||
bdUNK125();
|
||||
|
||||
private:
|
||||
void task_unk1(service_server* server, byte_buffer* buffer) const;
|
||||
void task_unk2(service_server* server, byte_buffer* buffer) const;
|
||||
void task_unk3(service_server* server, byte_buffer* buffer) const;
|
||||
void task_unk9(service_server* server, byte_buffer* buffer) const;
|
||||
};
|
||||
}
|
@ -5,6 +5,9 @@
|
||||
#define ID_ICON 102
|
||||
#define IMAGE_SPLASH 103
|
||||
|
||||
#define DW_PUBLISHER_OBJECTS_LIST 104
|
||||
#define DW_AUTH_TRAFFIC_SIGNING_KEY 105
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
|
@ -51,7 +51,7 @@ END
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
ID_ICON ICON "resources/icon.ico"
|
||||
ID_ICON ICON "resources/icon.ico"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -59,7 +59,10 @@ ID_ICON ICON "resources/icon.ico"
|
||||
// RCDATA
|
||||
//
|
||||
|
||||
IMAGE_SPLASH RCDATA "resources/splash.jpg"
|
||||
IMAGE_SPLASH RCDATA "resources/splash.jpg"
|
||||
|
||||
DW_PUBLISHER_OBJECTS_LIST RCDATA "resources/dw/publisher_objects_list.csv"
|
||||
DW_AUTH_TRAFFIC_SIGNING_KEY RCDATA "resources/dw/auth_traffic_signing_key.dat"
|
||||
|
||||
|
||||
#endif // English (United States) resources
|
||||
|
BIN
source/proxy-dll/resources/dw/auth_traffic_signing_key.dat
Normal file
BIN
source/proxy-dll/resources/dw/auth_traffic_signing_key.dat
Normal file
Binary file not shown.
12
source/proxy-dll/resources/dw/publisher_objects_list.csv
Normal file
12
source/proxy-dll/resources/dw/publisher_objects_list.csv
Normal file
@ -0,0 +1,12 @@
|
||||
arasafe_core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,2432,FCB3F6D4A4A21A2AE399E3D8F2430126
|
||||
arasafe_core_playlists_tu23_639_cf92ecf4a75d3f79.ff,2432,2C20B802AEA7FCDFF599BA40B554FB58
|
||||
core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,10315840,002F37761AF31051C400EC8DB5095062
|
||||
core_playlists_tu23_639_cf92ecf4a75d3f79.ff,30912,99DD77754218042A01D8F2D082028C68
|
||||
en_core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,38784,8C6ED0DCA0ECA3AF1B9811AC2108E5CE
|
||||
en_core_playlists_tu23_639_cf92ecf4a75d3f79.ff,25472,210E50AB866C9AFCBE7B866E5059C1DD
|
||||
gersafe_core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,2432,0120914E8A43330ECB5B211208E0763E
|
||||
gersafe_core_playlists_tu23_639_cf92ecf4a75d3f79.ff,2432,814775B5E27BE462607537852C9C42F1
|
||||
jpsafe_core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,2432,2D743D8D63B074A97151807CA502ABC4
|
||||
jpsafe_core_playlists_tu23_639_cf92ecf4a75d3f79.ff,2432,71BEA66B0385C06EB1F660A64F36654D
|
||||
k15safe_core_ffotd_tu23_639_cf92ecf4a75d3f79.ff,2432,8125C3EC0729F0D33C1373E60CD6D61B
|
||||
k15safe_core_playlists_tu23_639_cf92ecf4a75d3f79.ff,2432,4DB74A55B84648964E866132C66DFB3F
|
|
@ -563,6 +563,46 @@ namespace utils::cryptography
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
std::string md5::compute(const std::string& data, const bool hex)
|
||||
{
|
||||
return compute(cs(data.data()), data.size(), hex);
|
||||
}
|
||||
|
||||
std::string md5::compute(const uint8_t* data, const size_t length, const bool hex)
|
||||
{
|
||||
uint8_t buffer[16] = { 0 };
|
||||
|
||||
hash_state state;
|
||||
md5_init(&state);
|
||||
md5_process(&state, data, ul(length));
|
||||
md5_done(&state, buffer);
|
||||
|
||||
std::string hash(cs(buffer), sizeof(buffer));
|
||||
if (!hex) return hash;
|
||||
|
||||
return string::dump_hex(hash, "");
|
||||
}
|
||||
|
||||
uint32_t xxh32::compute(const std::string& data)
|
||||
{
|
||||
return compute(cs(data.data()), data.size());
|
||||
}
|
||||
|
||||
uint32_t xxh32::compute(const uint8_t* data, const size_t length)
|
||||
{
|
||||
return XXHash32::hash(data, length, 0);
|
||||
}
|
||||
|
||||
uint64_t xxh64::compute(const std::string& data)
|
||||
{
|
||||
return compute(cs(data.data()), data.size());
|
||||
}
|
||||
|
||||
uint64_t xxh64::compute(const uint8_t* data, const size_t length)
|
||||
{
|
||||
return XXHash64::hash(data, length, 0);
|
||||
}
|
||||
|
||||
std::string base64::encode(const uint8_t* data, const size_t len)
|
||||
{
|
||||
std::string result;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <tomcrypt.h>
|
||||
#include <xxhash32.h>
|
||||
#include <xxhash64.h>
|
||||
|
||||
namespace utils::cryptography
|
||||
{
|
||||
@ -96,6 +98,24 @@ namespace utils::cryptography
|
||||
std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
}
|
||||
|
||||
namespace md5
|
||||
{
|
||||
std::string compute(const std::string& data, bool hex = false);
|
||||
std::string compute(const uint8_t* data, size_t length, bool hex = false);
|
||||
}
|
||||
|
||||
namespace xxh32
|
||||
{
|
||||
uint32_t compute(const std::string& data);
|
||||
uint32_t compute(const uint8_t* data, size_t length);
|
||||
}
|
||||
|
||||
namespace xxh64
|
||||
{
|
||||
uint64_t compute(const std::string& data);
|
||||
uint64_t compute(const uint8_t* data, size_t length);
|
||||
}
|
||||
|
||||
namespace base64
|
||||
{
|
||||
std::string encode(const uint8_t* data, size_t len);
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include "smbios.hpp"
|
||||
#include "identity.hpp"
|
||||
#include "memory.hpp"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <intrin.h>
|
||||
#include <lmcons.h>
|
||||
|
||||
namespace utils::smbios
|
||||
namespace utils::identity
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@ -61,7 +62,19 @@ namespace utils::smbios
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_uuid()
|
||||
std::string get_sys_username()
|
||||
{
|
||||
char username[UNLEN + 1];
|
||||
DWORD username_len = UNLEN + 1;
|
||||
if (!GetUserNameA(username, &username_len))
|
||||
{
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
return std::string{ username, username_len - 1 };
|
||||
}
|
||||
|
||||
std::string get_sys_uuid()
|
||||
{
|
||||
auto smbios_data = get_smbios_data();
|
||||
auto* raw_data = reinterpret_cast<RawSMBIOSData*>(smbios_data.data());
|
9
source/shared-code/utils/identity.hpp
Normal file
9
source/shared-code/utils/identity.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils::identity
|
||||
{
|
||||
std::string get_sys_username();
|
||||
std::string get_sys_uuid();
|
||||
}
|
@ -78,6 +78,14 @@ namespace utils::io
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string file_name(const std::string& path)
|
||||
{
|
||||
const auto pos = path.find_last_of('/');
|
||||
if (pos == std::string::npos) return path;
|
||||
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
|
||||
size_t file_size(const std::string& file)
|
||||
{
|
||||
if (file_exists(file))
|
||||
@ -94,6 +102,13 @@ namespace utils::io
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t file_timestamp(const std::string& file)
|
||||
{
|
||||
const auto time = std::chrono::clock_cast<std::chrono::system_clock>(std::filesystem::last_write_time(file));
|
||||
|
||||
return std::chrono::system_clock::to_time_t(time);
|
||||
}
|
||||
|
||||
bool create_directory(const std::string& directory)
|
||||
{
|
||||
return std::filesystem::create_directories(directory);
|
||||
@ -115,6 +130,8 @@ namespace utils::io
|
||||
|
||||
for (auto& file : std::filesystem::directory_iterator(directory))
|
||||
{
|
||||
if (std::filesystem::is_directory(file.path())) continue;
|
||||
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,9 @@ namespace utils::io
|
||||
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||
bool read_file(const std::string& file, std::string* data);
|
||||
std::string read_file(const std::string& file);
|
||||
std::string file_name(const std::string& path);
|
||||
size_t file_size(const std::string& file);
|
||||
time_t file_timestamp(const std::string& file);
|
||||
bool create_directory(const std::string& directory);
|
||||
bool directory_exists(const std::string& directory);
|
||||
bool directory_is_empty(const std::string& directory);
|
||||
|
184
source/shared-code/utils/json_config.cpp
Normal file
184
source/shared-code/utils/json_config.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
#include "json_config.hpp"
|
||||
#include "io.hpp"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
namespace utils::json_config
|
||||
{
|
||||
rapidjson::Document json_doc{};
|
||||
std::string file_name = "project-bo4.json";
|
||||
|
||||
namespace
|
||||
{
|
||||
bool read_json_config()
|
||||
{
|
||||
std::string json_data{};
|
||||
if (!io::read_file(file_name, &json_data)) return false;
|
||||
|
||||
json_doc.Parse(json_data);
|
||||
|
||||
if (json_doc.HasParseError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool write_json_config()
|
||||
{
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
json_doc.Accept(writer);
|
||||
|
||||
std::string json_data(buffer.GetString(), buffer.GetLength());
|
||||
if (!io::write_file(file_name, json_data)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
rapidjson::Document& get_json_document()
|
||||
{
|
||||
static bool json_initialized = false;
|
||||
if (!json_initialized)
|
||||
{
|
||||
if (!read_json_config()) {
|
||||
json_doc = rapidjson::Document(rapidjson::kObjectType);
|
||||
}
|
||||
|
||||
json_initialized = true;
|
||||
}
|
||||
|
||||
/*if (json_doc != NULL) */return json_doc;
|
||||
}
|
||||
|
||||
rapidjson::Value& get_json_section(const char* szSection)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
|
||||
if (!doc.HasMember(szSection))
|
||||
{
|
||||
doc.AddMember(rapidjson::StringRef(szSection), rapidjson::kObjectType, doc.GetAllocator());
|
||||
}
|
||||
|
||||
rapidjson::Value& section = doc[szSection];
|
||||
|
||||
if (!section.IsObject()) section.SetObject();
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
std::string ReadString(const char* szSection, const char* szKey, const std::string& strDefaultValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), strDefaultValue, doc.GetAllocator());
|
||||
}
|
||||
else if (!section[szKey].IsString()) {
|
||||
section[szKey].SetString(strDefaultValue, doc.GetAllocator());
|
||||
}
|
||||
else {
|
||||
return section[szKey].GetString();
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
return section[szKey].GetString();
|
||||
}
|
||||
|
||||
void WriteString(const char* szSection, const char* szKey, const std::string& strValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), strValue, doc.GetAllocator());
|
||||
}
|
||||
else {
|
||||
section[szKey].SetString(strValue, doc.GetAllocator());
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
}
|
||||
|
||||
unsigned int ReadUnsignedInteger(const char* szSection, const char* szKey, unsigned int iDefaultValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), iDefaultValue, doc.GetAllocator());
|
||||
}
|
||||
else if (!section[szKey].IsUint()) {
|
||||
section[szKey].SetUint(iDefaultValue);
|
||||
}
|
||||
else {
|
||||
return section[szKey].GetUint();
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
return section[szKey].GetUint();
|
||||
}
|
||||
|
||||
int ReadInteger(const char* szSection, const char* szKey, int iDefaultValue)
|
||||
{
|
||||
return static_cast<int>(ReadUnsignedInteger(szSection, szKey, static_cast<unsigned int>(iDefaultValue)));
|
||||
}
|
||||
|
||||
void WriteUnsignedInteger(const char* szSection, const char* szKey, unsigned int iValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), iValue, doc.GetAllocator());
|
||||
}
|
||||
else {
|
||||
section[szKey].SetUint(iValue);
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
}
|
||||
|
||||
void WriteInteger(const char* szSection, const char* szKey, int iValue)
|
||||
{
|
||||
ReadUnsignedInteger(szSection, szKey, static_cast<unsigned int>(iValue));
|
||||
}
|
||||
|
||||
bool ReadBoolean(const char* szSection, const char* szKey, bool bolDefaultValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), bolDefaultValue, doc.GetAllocator());
|
||||
}
|
||||
else if (!section[szKey].IsBool()) {
|
||||
section[szKey].SetBool(bolDefaultValue);
|
||||
}
|
||||
else {
|
||||
return section[szKey].GetBool();
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
return section[szKey].GetBool();
|
||||
}
|
||||
|
||||
void WriteBoolean(const char* szSection, const char* szKey, bool bolValue)
|
||||
{
|
||||
rapidjson::Document& doc = get_json_document();
|
||||
rapidjson::Value& section = get_json_section(szSection);
|
||||
|
||||
if (!section.HasMember(szKey)) {
|
||||
section.AddMember(rapidjson::StringRef(szKey), bolValue, doc.GetAllocator());
|
||||
}
|
||||
else {
|
||||
section[szKey].SetBool(bolValue);
|
||||
}
|
||||
|
||||
write_json_config();
|
||||
}
|
||||
}
|
17
source/shared-code/utils/json_config.hpp
Normal file
17
source/shared-code/utils/json_config.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace utils::json_config
|
||||
{
|
||||
std::string ReadString(const char* szSection, const char* szKey, const std::string& strDefaultValue);
|
||||
void WriteString(const char* szSection, const char* szKey, const std::string& strValue);
|
||||
|
||||
unsigned int ReadUnsignedInteger(const char* szSection, const char* szKey, unsigned int iDefaultValue);
|
||||
void WriteUnsignedInteger(const char* szSection, const char* szKey, unsigned int iValue);
|
||||
|
||||
int ReadInteger(const char* szSection, const char* szKey, int iDefaultValue);
|
||||
void WriteInteger(const char* szSection, const char* szKey, int iValue);
|
||||
|
||||
bool ReadBoolean(const char* szSection, const char* szKey, bool bolDefaultValue);
|
||||
void WriteBoolean(const char* szSection, const char* szKey, bool bolValue);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils::smbios
|
||||
{
|
||||
std::string get_uuid();
|
||||
}
|
@ -34,6 +34,23 @@ namespace utils::string
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& s, const std::string& delim)
|
||||
{
|
||||
size_t pos_start = 0, pos_end, delim_len = delim.length();
|
||||
std::string token;
|
||||
std::vector<std::string> elems;
|
||||
|
||||
while ((pos_end = s.find(delim, pos_start)) != std::string::npos) {
|
||||
token = s.substr(pos_start, pos_end - pos_start);
|
||||
pos_start = pos_end + delim_len;
|
||||
elems.push_back(token);
|
||||
}
|
||||
|
||||
elems.push_back(s.substr(pos_start));
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::string to_lower(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
|
@ -81,6 +81,7 @@ namespace utils::string
|
||||
const char* va(const char* fmt, ...);
|
||||
|
||||
std::vector<std::string> split(const std::string& s, char delim);
|
||||
std::vector<std::string> split(const std::string& s, const std::string& delim);
|
||||
|
||||
std::string to_lower(std::string text);
|
||||
std::string to_upper(std::string text);
|
||||
|
Loading…
Reference in New Issue
Block a user