/* Copyright (C) 2019 Mr Goldberg
This file is part of the Goldberg Emulator
The Goldberg Emulator is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
The Goldberg Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the Goldberg Emulator; if not, see
. */
#include "dll/appticket.h"
void AppTicketV1::Reset()
{
TicketSize = 0;
TicketVersion = 0;
Unk2 = 0;
UserData.clear();
}
std::vector AppTicketV1::Serialize() const
{
std::vector buffer{};
uint8_t* pBuffer{};
buffer.resize(16 + UserData.size());
pBuffer = buffer.data();
*reinterpret_cast(pBuffer) = TicketSize; pBuffer += 4;
*reinterpret_cast(pBuffer) = TicketVersion; pBuffer += 4;
*reinterpret_cast(pBuffer) = UserData.size(); pBuffer += 4;
*reinterpret_cast(pBuffer) = Unk2; pBuffer += 4;
memcpy(pBuffer, UserData.data(), UserData.size());
return buffer;
}
bool AppTicketV1::Deserialize(const uint8_t* pBuffer, size_t size)
{
if (size < 16)
return false;
uint32_t user_data_size;
TicketSize = *reinterpret_cast(pBuffer); pBuffer += 4;
TicketVersion = *reinterpret_cast(pBuffer); pBuffer += 4;
user_data_size = *reinterpret_cast(pBuffer); pBuffer += 4;
if (size < (user_data_size + 16))
return false;
Unk2 = *reinterpret_cast(pBuffer); pBuffer += 4;
UserData.resize(user_data_size);
memcpy(UserData.data(), pBuffer, user_data_size);
return true;
}
void AppTicketV2::Reset()
{
TicketSize = 0;
TicketVersion = 0;
SteamID = 0;
AppID = 0;
Unk1 = 0;
Unk2 = 0;
TicketFlags = 0;
TicketIssueTime = 0;
TicketValidityEnd = 0;
}
std::vector AppTicketV2::Serialize() const
{
std::vector buffer{};
uint8_t* pBuffer{};
buffer.resize(40);
pBuffer = buffer.data();
*reinterpret_cast(pBuffer) = TicketSize; pBuffer += 4;
*reinterpret_cast(pBuffer) = TicketVersion; pBuffer += 4;
*reinterpret_cast(pBuffer) = SteamID; pBuffer += 8;
*reinterpret_cast(pBuffer) = AppID; pBuffer += 4;
*reinterpret_cast(pBuffer) = Unk1; pBuffer += 4;
*reinterpret_cast(pBuffer) = Unk2; pBuffer += 4;
*reinterpret_cast(pBuffer) = TicketFlags; pBuffer += 4;
*reinterpret_cast(pBuffer) = TicketIssueTime; pBuffer += 4;
*reinterpret_cast(pBuffer) = TicketValidityEnd;
return buffer;
}
bool AppTicketV2::Deserialize(const uint8_t* pBuffer, size_t size)
{
if (size < 40)
return false;
TicketSize = *reinterpret_cast(pBuffer); pBuffer += 4;
TicketVersion = *reinterpret_cast(pBuffer); pBuffer += 4;
SteamID = *reinterpret_cast(pBuffer); pBuffer += 8;
AppID = *reinterpret_cast(pBuffer); pBuffer += 4;
Unk1 = *reinterpret_cast(pBuffer); pBuffer += 4;
Unk2 = *reinterpret_cast(pBuffer); pBuffer += 4;
TicketFlags = *reinterpret_cast(pBuffer); pBuffer += 4;
TicketIssueTime = *reinterpret_cast(pBuffer); pBuffer += 4;
TicketValidityEnd = *reinterpret_cast(pBuffer);
return true;
}
void AppTicketV4::Reset()
{
AppIDs.clear();
HasVACStatus = false;
HasAppValue = false;
}
std::vector AppTicketV4::Serialize()
{
std::vector appids = AppIDs;
if (appids.size() == 0) {
appids.emplace_back(0);
}
uint16_t appid_count = static_cast(appids.size() > 140 ? 140 : appids.size());
size_t buffer_size = static_cast(appid_count) * 4ul + 2ul;
std::vector buffer{};
uint8_t* pBuffer{};
if (HasAppValue) {// VACStatus + AppValue
buffer_size += 4;
if (!HasVACStatus) {
HasVACStatus = true;
VACStatus = 0;
}
}
if (HasVACStatus) {// VACStatus only
buffer_size += 4;
}
buffer.resize(buffer_size);
pBuffer = buffer.data();
*reinterpret_cast(pBuffer) = appid_count;
pBuffer += 2;
for (int i = 0; i < appid_count && i < 140; ++i) {
*reinterpret_cast(pBuffer) = appids[i];
pBuffer += 4;
}
if (HasVACStatus) {
*reinterpret_cast(pBuffer) = VACStatus;
pBuffer += 4;
}
if (HasAppValue) {
*reinterpret_cast(pBuffer) = AppValue;
}
return buffer;
}
bool AppTicketV4::Deserialize(const uint8_t* pBuffer, size_t size)
{
if (size < 2)
return false;
uint16_t appid_count = *reinterpret_cast(pBuffer);
if (size < (appid_count * 4 + 2) || appid_count >= 140)
return false;
AppIDs.resize(appid_count);
pBuffer += 2;
size -= 2;
for (int i = 0; i < appid_count; ++i) {
AppIDs[i] = *reinterpret_cast(pBuffer);
pBuffer += 4;
size -= 4;
}
HasVACStatus = false;
HasAppValue = false;
if (size < 4)
return true;
HasVACStatus = true;
VACStatus = *reinterpret_cast(pBuffer);
pBuffer += 4;
size -= 4;
if (size < 4)
return true;
HasAppValue = true;
AppValue = *reinterpret_cast(pBuffer);
return true;
}
bool DecryptedAppTicket::DeserializeTicket(const uint8_t* pBuffer, size_t buf_size)
{
if (!TicketV1.Deserialize(pBuffer, buf_size))
return false;
pBuffer += 16 + TicketV1.UserData.size();
buf_size -= 16 + TicketV1.UserData.size();
if (!TicketV2.Deserialize(pBuffer, buf_size))
return false;
if (TicketV2.TicketVersion > 2) {
pBuffer += 40;
buf_size -= 40;
if (!TicketV4.Deserialize(pBuffer, buf_size))
return false;
}
return true;
}
std::vector DecryptedAppTicket::SerializeTicket()
{
std::vector buffer{};
TicketV1.TicketSize = TicketV1.UserData.size() + 40 + 2 + ((TicketV4.AppIDs.size() == 0 ? 1 : TicketV4.AppIDs.size()) * 4) + (TicketV4.HasVACStatus ? 4 : 0) + (TicketV4.HasAppValue ? 4 : 0);
TicketV2.TicketSize = TicketV1.TicketSize - TicketV1.UserData.size();
buffer = TicketV1.Serialize();
auto v = TicketV2.Serialize();
buffer.insert(buffer.end(), v.begin(), v.end());
v = TicketV4.Serialize();
buffer.insert(buffer.end(), v.begin(), v.end());
return buffer;
}
Steam_AppTicket::Steam_AppTicket(class Settings *settings) :
settings(settings)
{
}
uint32 Steam_AppTicket::GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature )
{
PRINT_DEBUG("TODO %u, %p, %u, %p, %p, %p, %p", nAppID, pvBuffer, cbBufferLength, piAppId, piSteamId, piSignature, pcbSignature);
std::lock_guard lock(global_mutex);
return 0;
}