fix: security vulnerabilities

Tested that all functions related to the touched files work

will test sqlite on a CI build
This commit is contained in:
David Markowitz
2026-06-06 23:13:09 -07:00
parent 8e09ffd6e8
commit fb166bd24d
107 changed files with 786 additions and 512 deletions

View File

@@ -478,6 +478,7 @@ std::vector<LWOOBJID> BaseCombatAIComponent::GetTargetWithinAggroRange() const {
for (auto id : m_Parent->GetTargetsInPhantom()) {
auto* other = Game::entityManager->GetEntity(id);
if (!other) continue;
const auto distance = Vector3::DistanceSquared(m_Parent->GetPosition(), other->GetPosition());

View File

@@ -450,19 +450,10 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
param.value = result.getFloatField("NumberValue");
param.effectId = result.getIntField("EffectID");
if (!result.fieldIsNull("StringValue")) {
std::istringstream stream(result.getStringField("StringValue"));
std::string token;
while (std::getline(stream, token, ',')) {
try {
const auto value = std::stof(token);
param.values.push_back(value);
} catch (std::invalid_argument& exception) {
LOG("Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
}
for (const auto& str : GeneralUtils::SplitString(result.getStringField("StringValue"), ',')) {
if (str.empty()) continue;
const auto value = GeneralUtils::TryParse<float>(str);
if (value) param.values.push_back(value.value());
}
parameters.push_back(param);

View File

@@ -797,8 +797,14 @@ std::string CharacterComponent::StatisticsToString() const {
return result.str();
}
uint64_t CharacterComponent::GetStatisticFromSplit(std::vector<std::string> split, uint32_t index) {
return split.size() > index ? std::stoull(split.at(index)) : 0;
uint64_t CharacterComponent::GetStatisticFromSplit(const std::vector<std::string>& split, const uint32_t index) {
uint64_t toReturn = 0;
if (index < split.size()) {
const auto parsed = GeneralUtils::TryParse<uint64_t>(split[index]);
if (parsed) toReturn = *parsed;
}
return toReturn;
}
ZoneStatistics& CharacterComponent::GetZoneStatisticsForMap(LWOMAPID mapID) {

View File

@@ -450,7 +450,7 @@ private:
* @param index the statistics ID in the string
* @return the integer value of this statistic, parsed from the string
*/
static uint64_t GetStatisticFromSplit(std::vector<std::string> split, uint32_t index);
static uint64_t GetStatisticFromSplit(const std::vector<std::string>& split, const uint32_t index);
/**
* Gets all the statistics for a certain map, if it doesn't exist, it creates empty stats
@@ -526,6 +526,7 @@ private:
/**
* Total amount of meters traveled by this character
* Should be a double and then truncated so decimals can be tracked
*/
uint64_t m_MetersTraveled;

View File

@@ -793,7 +793,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
if (!zoneControl || scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
scriptEntity->GetScript()->OnPlayerDied(scriptEntity, m_Parent);
}
}
@@ -964,6 +964,8 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
if (m_Parent->IsPlayer()) {
//remove hardcore_lose_uscore_on_death_percent from the player's uscore:
auto* character = m_Parent->GetComponent<CharacterComponent>();
if (!character) return;
auto uscore = character->GetUScore();
auto uscoreToLose = static_cast<uint64_t>(uscore * (Game::entityManager->GetHardcoreLoseUscoreOnDeathPercent() / 100.0f));

View File

@@ -966,8 +966,9 @@ void InventoryComponent::EquipScripts(Item* equippedItem) {
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
if (!itemScript) {
LOG("null script?");
} else {
itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId());
}
itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId());
}
}
@@ -981,8 +982,9 @@ void InventoryComponent::UnequipScripts(Item* unequippedItem) {
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
if (!itemScript) {
LOG("null script?");
} else {
itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId());
}
itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId());
}
}
@@ -1633,7 +1635,7 @@ void InventoryComponent::LoadPetXml(const tinyxml2::XMLDocument& document) {
DatabasePet databasePet;
databasePet.lot = lot;
databasePet.moderationState = moderationStatus;
databasePet.name = std::string(name);
databasePet.name = name ? name : "";
SetDatabasePet(id, databasePet);

View File

@@ -22,7 +22,7 @@ public:
void NextLUPExhibit();
private:
float m_UpdateTimer = 0.0f;
std::array<LOT, 4> m_LUPExhibits = { 11121, 11295, 11423, 11979 };
const std::array<LOT, 4> m_LUPExhibits = { 11121, 11295, 11423, 11979 };
uint8_t m_LUPExhibitIndex = 0;
bool m_DirtyLUPExhibit = true;
};

View File

@@ -449,45 +449,48 @@ void MissionComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) {
if (mis == nullptr) return;
auto* cur = mis->FirstChildElement("cur");
auto* done = mis->FirstChildElement("done");
auto* doneM = done->FirstChildElement();
while (doneM) {
int missionId;
doneM->QueryAttribute("id", &missionId);
auto* mission = new Mission(this, missionId);
mission->LoadFromXmlDone(*doneM);
doneM = doneM->NextSiblingElement();
m_Missions.insert_or_assign(missionId, mission);
}
auto* currentM = cur->FirstChildElement();
uint32_t missionOrder{};
while (currentM) {
int missionId;
currentM->QueryAttribute("id", &missionId);
auto* mission = m_Missions.contains(missionId) ? m_Missions[missionId] : new Mission(this, missionId);
mission->LoadFromXmlCur(*currentM);
if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) {
mission->SetUniqueMissionOrderID(missionOrder);
if (missionOrder > m_LastUsedMissionOrderUID) m_LastUsedMissionOrderUID = missionOrder;
if (done) {
auto* doneM = done->FirstChildElement();
while (doneM) {
int missionId;
doneM->QueryAttribute("id", &missionId);
auto* mission = new Mission(this, missionId);
mission->LoadFromXmlDone(*doneM);
doneM = doneM->NextSiblingElement();
m_Missions.insert_or_assign(missionId, mission);
}
}
auto* cur = mis->FirstChildElement("cur");
if (cur) {
auto* currentM = cur->FirstChildElement();
currentM = currentM->NextSiblingElement();
uint32_t missionOrder{};
while (currentM) {
int missionId;
m_Missions.insert_or_assign(missionId, mission);
currentM->QueryAttribute("id", &missionId);
auto* mission = m_Missions.contains(missionId) ? m_Missions[missionId] : new Mission(this, missionId);
mission->LoadFromXmlCur(*currentM);
if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) {
mission->SetUniqueMissionOrderID(missionOrder);
if (missionOrder > m_LastUsedMissionOrderUID) m_LastUsedMissionOrderUID = missionOrder;
}
currentM = currentM->NextSiblingElement();
m_Missions.insert_or_assign(missionId, mission);
}
}
}

View File

@@ -17,7 +17,10 @@ MultiZoneEntranceComponent::MultiZoneEntranceComponent(Entity* parent, const int
MultiZoneEntranceComponent::~MultiZoneEntranceComponent() {}
void MultiZoneEntranceComponent::OnUse(Entity* originator) {
auto* rocket = originator->GetComponent<CharacterComponent>()->RocketEquip(originator);
auto* const characterComponent = originator->GetComponent<CharacterComponent>();
if (!characterComponent) return;
auto* rocket = characterComponent->RocketEquip(originator);
if (!rocket) return;
// the LUP world menu is just the property menu, the client knows how to handle it
@@ -26,7 +29,7 @@ void MultiZoneEntranceComponent::OnUse(Entity* originator) {
void MultiZoneEntranceComponent::OnSelectWorld(Entity* originator, uint32_t index) {
auto* rocketLaunchpadControlComponent = m_Parent->GetComponent<RocketLaunchpadControlComponent>();
if (!rocketLaunchpadControlComponent) return;
if (!rocketLaunchpadControlComponent || index >= m_LUPWorlds.size()) return;
rocketLaunchpadControlComponent->Launch(originator, m_LUPWorlds[index], 0);
}

View File

@@ -922,7 +922,9 @@ void PetComponent::Deactivate() {
}
void PetComponent::Release() {
auto* inventoryComponent = GetOwner()->GetComponent<InventoryComponent>();
auto* const owner = GetOwner();
if (!owner) return;
auto* const inventoryComponent = owner->GetComponent<InventoryComponent>();
if (inventoryComponent == nullptr) {
return;
@@ -932,9 +934,9 @@ void PetComponent::Release() {
inventoryComponent->RemoveDatabasePet(m_DatabaseId);
auto* item = inventoryComponent->FindItemBySubKey(m_DatabaseId);
auto* const item = inventoryComponent->FindItemBySubKey(m_DatabaseId);
item->SetCount(0, false, false);
if (item) item->SetCount(0, false, false);
}
void PetComponent::Command(const NiPoint3& position, const LWOOBJID source, const int32_t commandType, const int32_t typeId, const bool overrideObey) {

View File

@@ -58,31 +58,15 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent, const int32_t c
}
if (m_IsRespawnVolume) {
{
auto respawnString = std::stringstream(m_Parent->GetVarAsString(u"rspPos"));
const auto respawnPos = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rspPos"), '\x1f');
m_RespawnPos = GeneralUtils::TryParse(respawnPos, NiPoint3Constant::ZERO);
std::string segment;
std::vector<std::string> seglist;
while (std::getline(respawnString, segment, '\x1f')) {
seglist.push_back(segment);
}
m_RespawnPos = NiPoint3(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]));
}
{
auto respawnString = std::stringstream(m_Parent->GetVarAsString(u"rspRot"));
std::string segment;
std::vector<std::string> seglist;
while (std::getline(respawnString, segment, '\x1f')) {
seglist.push_back(segment);
}
m_RespawnRot = NiQuaternion(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]), std::stof(seglist[3]));
}
const auto respawnRot = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rspRot"), '\x1f');
m_RespawnRot = NiQuaternion(
GeneralUtils::TryParse(respawnRot[0], 1.0f),
GeneralUtils::TryParse(respawnRot[1], 0.0f),
GeneralUtils::TryParse(respawnRot[2], 0.0f),
GeneralUtils::TryParse(respawnRot[3], 0.0f));
}
// HF - RespawnPoints. Legacy respawn entity.

View File

@@ -131,7 +131,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
const auto lookupResult = Database::Get()->GetProperties(propertyLookup);
for (const auto& propertyEntry : lookupResult->entries) {
for (const auto& propertyEntry : lookupResult.entries) {
const auto owner = propertyEntry.ownerId;
const auto otherCharacter = Database::Get()->GetCharacterInfo(owner);
if (!otherCharacter.has_value()) {
@@ -174,5 +174,5 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
}
// Query here is to figure out whether or not to display the button to go to the next page or not.
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, lookupResult->totalEntriesMatchingQuery - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr);
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, lookupResult.totalEntriesMatchingQuery - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr);
}

View File

@@ -107,20 +107,12 @@ std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const {
std::vector<float> points;
std::istringstream stream(result.getStringField("path"));
std::string token;
while (std::getline(stream, token, ' ')) {
try {
auto value = std::stof(token);
points.push_back(value);
} catch (std::invalid_argument& exception) {
LOG("Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
for (const auto& str : GeneralUtils::SplitString(result.getStringField("path"), ' ')) {
const auto value = GeneralUtils::TryParse<float>(str);
if (value) points.push_back(value.value());
}
for (auto i = 0u; i < points.size(); i += 3) {
for (auto i = 0u; i + 2 < points.size(); i += 3) {
paths.emplace_back(points[i], points[i + 1], points[i + 2]);
}
@@ -780,15 +772,17 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const
privacy = static_cast<char>(this->privacyOption);
if (moderatorRequested) {
auto moderationInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId);
if (moderationInfo->rejectionReason != "") {
moderatorRequested = false;
rejectionReason = moderationInfo->rejectionReason;
} else if (moderationInfo->rejectionReason == "" && moderationInfo->modApproved == 1) {
moderatorRequested = false;
rejectionReason = "";
} else {
moderatorRequested = true;
rejectionReason = "";
if (moderationInfo) {
if (moderationInfo->rejectionReason != "") {
moderatorRequested = false;
rejectionReason = moderationInfo->rejectionReason;
} else if (moderationInfo->rejectionReason == "" && moderationInfo->modApproved == 1) {
moderatorRequested = false;
rejectionReason = "";
} else {
moderatorRequested = true;
rejectionReason = "";
}
}
}
}

View File

@@ -380,7 +380,7 @@ void QuickBuildComponent::StartQuickBuild(Entity* const user) {
m_Builder = user->GetObjectID();
auto* character = user->GetComponent<CharacterComponent>();
character->SetCurrentActivity(eGameActivity::QUICKBUILDING);
if (character) character->SetCurrentActivity(eGameActivity::QUICKBUILDING);
Game::entityManager->SerializeEntity(user);

View File

@@ -306,7 +306,7 @@ void RacingControlComponent::OnRequestDie(Entity* player, const std::u16string&
eKillType::VIOLENT, deathType, 0, 0, 90.0f, false, true, 0);
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
uint32_t respawnImagination = 0;
int32_t respawnImagination = 0;
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
// Do not actually change the value yet. Do that on respawn.
if (destroyableComponent) {

View File

@@ -385,26 +385,30 @@ void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::v
}
phantomPhysicsComponent->SetPhysicsEffectActive(true);
ePhysicsEffectType effectType = ePhysicsEffectType::PUSH;
std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase
if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH;
else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT;
else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE;
else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE;
else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION;
if (!argArray.empty()) {
std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase
if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH;
else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT;
else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE;
else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE;
else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION;
}
phantomPhysicsComponent->SetEffectType(effectType);
phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1)));
if (argArray.size() > 1) {
phantomPhysicsComponent->SetDirectionalMultiplier(GeneralUtils::TryParse(argArray.at(1), 0.0f));
}
if (argArray.size() > 4) {
const NiPoint3 direction =
GeneralUtils::TryParse<NiPoint3>(argArray.at(2), argArray.at(3), argArray.at(4)).value_or(NiPoint3Constant::ZERO);
GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), NiPoint3Constant::ZERO);
phantomPhysicsComponent->SetDirection(direction);
}
if (argArray.size() > 5) {
const uint32_t min = GeneralUtils::TryParse<uint32_t>(argArray.at(6)).value_or(0);
const uint32_t min = GeneralUtils::TryParse(argArray.at(6), 0);
phantomPhysicsComponent->SetMin(min);
const uint32_t max = GeneralUtils::TryParse<uint32_t>(argArray.at(7)).value_or(0);
const uint32_t max = GeneralUtils::TryParse(argArray.at(7), 0);
phantomPhysicsComponent->SetMax(max);
}