Skip to content

refactor: remove all Boost library dependencies#2

Open
Mateuzkl wants to merge 1 commit into
mainfrom
c23++
Open

refactor: remove all Boost library dependencies#2
Mateuzkl wants to merge 1 commit into
mainfrom
c23++

Conversation

@Mateuzkl

@Mateuzkl Mateuzkl commented Jun 4, 2026

Copy link
Copy Markdown
Owner
  • Removed boost-* dependencies from vcpkg.json and integrated standalone asio.
  • Cleaned up CMake build files, removing FindBoost.cmake and Boost configurations.
  • Migrated boost::asio and boost::system::error_code usages to standalone asio.
  • Re-implemented HTTP/HTTPS (HttpSession) and WebSocket/WSS (WebsocketSession) using standalone asio + OpenSSL/SSL stream, removing boost::beast entirely.
  • Replaced boost::filesystem with std::filesystem.
  • Replaced boost::uuids with a custom name-generator UUIDv5 implementation to preserve exact decrypter compatibility.
  • Replaced boost::process with native Windows (CreateProcessW) and Unix (fork/waitpid) process execution.
  • Replaced boost::tokenizer in OTML parsing with a lightweight native CSV-style parser.
  • Replaced boost::algorithm::unhex with a standard hexadecimal to binary conversion helper.
  • Removed boost includes from pch.h and defined ASIO_STANDALONE.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed type handling in animated text merging logic
    • Corrected HTTP string initialization in file stream operations
    • Improved network error handling and connection management
    • Enhanced floating-point precision in minimap rendering calculations
    • Fixed distance calculation in tile shooting mechanics
  • Improvements

    • Refactored HTTP and WebSocket connection handling for improved reliability
    • Optimized network protocol stack and error reporting
    • Enhanced build system with modern C++ standard support (C++23)
    • Streamlined platform-specific process launching
    • Improved cryptographic key derivation and UUID generation

- Removed boost-* dependencies from vcpkg.json and integrated standalone asio.
- Cleaned up CMake build files, removing FindBoost.cmake and Boost configurations.
- Migrated boost::asio and boost::system::error_code usages to standalone asio.
- Re-implemented HTTP/HTTPS (HttpSession) and WebSocket/WSS (WebsocketSession) using standalone asio + OpenSSL/SSL stream, removing boost::beast entirely.
- Replaced boost::filesystem with std::filesystem.
- Replaced boost::uuids with a custom name-generator UUIDv5 implementation to preserve exact decrypter compatibility.
- Replaced boost::process with native Windows (CreateProcessW) and Unix (fork/waitpid) process execution.
- Replaced boost::tokenizer in OTML parsing with a lightweight native CSV-style parser.
- Replaced boost::algorithm::unhex with a standard hexadecimal to binary conversion helper.
- Removed boost includes from pch.h and defined ASIO_STANDALONE.
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Este PR substitui Boost.Asio por Asio standalone em toda a rede assíncrona, reimplementa HTTP/WebSocket sem Boost.Beast, remove outras dependências Boost (UUID, strings, processos), atualiza build para C++23, com mudanças sistemáticas a arquivos de cliente, framework e configuração.

Changes

Migração Asio e Remoção de Dependências Boost

Layer / File(s) Summary
Fundação: PCH e declarações de namespace
src/framework/pch.h, src/framework/net/declarations.h
Define ASIO_STANDALONE e substitui headers Boost.Asio/Beast por asio.hpp e asio/ssl.hpp; remove alias global namespace asio = boost::asio.
Camada de conexão: tipos de erro e callbacks
src/framework/net/connection.h, src/framework/net/connection.cpp
Substitui boost::system::error_code por asio::error_code em ErrorCallback, getError() e handlers protegidos (onResolve, onConnect, onCanWrite, onWrite, onRecv, onTimeout); atualiza opções de socket para asio::socket_base.
Protocol base: callbacks e dispatch assíncrono
src/framework/net/protocol.h, src/framework/net/protocol.cpp
Migra onError e onLocalDisconnected para asio::error_code, substitui boost::asio::post por asio::post em deferred handlers.
Protocolo de jogo do cliente
src/client/game.h, src/client/game.cpp, src/client/protocolgame.h, src/client/protocolgame.cpp
Atualiza Game::processConnectionError e ProtocolGame::onError para asio::error_code; torna UnjustifiedPoints::operator== const.
Cliente HTTP/HTTPS com construção manual e SSL
src/framework/http/session.h, src/framework/http/session.cpp, src/framework/http/http.h, src/framework/http/http.cpp
Reimplementa HttpSession com construção manual HTTP/1.1, parsing de headers e corpo, suporte a chunked; usa asio::ssl::stream e async_read_until em lugar de Boost.Beast; atualiza Http para asio::io_context e asio::post.
Cliente WebSocket com handshake e frames manuais
src/framework/http/websocket.h, src/framework/http/websocket.cpp
Remove Boost.Beast WebSocket, implementa handshake HTTP manual, funções buildWebSocketFrame e parseWebSocketFrame locais, leitura/escrita assíncrona com async_read_some/async_write.
Proxy TCP/IP com resolução e sockets Asio
src/framework/proxy/proxy.h, src/framework/proxy/proxy.cpp, src/framework/proxy/proxy_client.h, src/framework/proxy/proxy_client.cpp
Migra Proxy e Session para asio::io_context, asio::ip::tcp::socket, asio::error_code; atualiza resolução DNS, conexão TCP e handlers de pacotes.
Utilitários de rede: conversão de IP com Asio
src/framework/stdext/net.cpp
Substitui boost::asio::ip por asio::ip::address_v4 e asio::detail::socket_ops para conversão IP.
Algoritmos de string: remoção de Boost.Algorithm
src/framework/stdext/string.cpp
Remove boost::algorithm e implementa manualmente trim, replace_all, split, starts_with, ends_with com C++ padrão.
Normalização de caminhos Windows com stdext
src/framework/platform/win32platform.cpp
Substitui boost::replace_all e boost::ends_with por stdext equivalentes em spawnProcess, getTempPath, getCurrentDir, fileExists, copyFile, removeFile.
Tradução de UI com normalização de strings
src/framework/ui/uitranslator.cpp
Atualiza translateAlignment, translateAnchorEdge, translateState, translateAutoFocusPolicy para usar stdext::tolower e stdext::trim.
Parser OTML com tokenização manual
src/framework/otml/otmlparser.cpp
Remove boost::tokenizer e implementa analisador manual para listas em [...] respeitando aspas duplas e escapes.
Gerenciamento de processos sem Boost.Process
src/framework/core/application.cpp, src/framework/core/resourcemanager.cpp
Remove boost::process::child e implementa chamadas diretas: CreateProcessW (Windows) e fork/execl (POSIX) com espera não-bloqueante.
Criptografia e UUID com C++ padrão
src/framework/util/crypt.h, src/framework/util/crypt.cpp
Remove boost::uuid e substitui genUUID, getMachineUUID, getCryptKey por implementações com std::random_device, SHA1, std::array<uint8_t, 16>.
Correções menores e limpeza
src/framework/core/filestream.cpp, src/framework/xml/tinyxml.cpp, src/client/animatedtext.cpp, src/client/tile.cpp, src/framework/sound/streamsoundsource.cpp
Corrige inicialização em FileStream::getString, TiXmlElement::Attribute; adds float casts em AnimatedText::merge, Tile::canShoot; remove boost/concept_check.hpp.
Cálculos em ponto flutuante no minimapa
src/client/minimap.cpp
Atualiza Minimap::draw com casts float explícitos em MMBLOCK_SIZE*scale para iterações e destino.

Configurações de Build e Ferramentas

Layer / File(s) Summary
Configuração CMake para Asio standalone
src/framework/CMakeLists.txt
Remove find_package(Boost) e seus includes/libraries, adiciona find_package(asio CONFIG REQUIRED) e asio::asio às bibliotecas do framework.
Atualização de toolset e C++ standard
vc23/otclient.vcxproj
Atualiza PlatformToolset de v143 para v145 e LanguageStandard de stdcpp17 para stdcpp23 em todas as configurações.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Boost removido, Asio no lugar,
HTTP manual, WebSocket sem Beast a remar,
C++23 brilha, sem Boost a seguir,
Strings e UUIDs próprios, só stdlib a vir! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título descreve com precisão o objetivo principal do PR: remover todas as dependências da biblioteca Boost do projeto.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch c23++

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud

sonarqubecloud Bot commented Jun 4, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
3 Security Hotspots
3.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/framework/CMakeLists.txt (1)

171-171: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Alinhe o padrão C++ do CMake com o .vcxproj

O CMake continua fixando CMAKE_CXX_STANDARD em 17 (src/framework/CMakeLists.txt:171 e também CMakeLists.txt:8), enquanto o Visual Studio vc23/otclient.vcxproj usa <LanguageStandard>stdcpp23</LanguageStandard>. Isso cria builds inconsistentes e pode quebrar código esperado para C++23 ao compilar via CMake.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/CMakeLists.txt` at line 171, Atualize a definição do padrão C++
nos CMakeLists onde aparece set(CMAKE_CXX_STANDARD 17) para usar 23
(CMAKE_CXX_STANDARD 23) e force o comportamento consistente adicionando também
set(CMAKE_CXX_STANDARD_REQUIRED ON) e set(CMAKE_CXX_EXTENSIONS OFF) próximo a
essas linhas; corrija ambas as ocorrências do CMakeLists para alinhar com o
LanguageStandard usado no projeto (referência: o símbolo CMAKE_CXX_STANDARD e
onde é definido).
src/framework/core/application.cpp (1)

183-197: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Garantir relançamento antes de encerrar o processo (restart/restartArgs)

Application::restart() e Application::restartArgs() chamam g_platform.spawnProcess(...) e depois fazem quick_exit() sem checar o retorno. No Unix (src/framework/platform/unixplatform.cpp), spawnProcess(...) retorna bool e implementa fork()/exec — se spawnProcess puder retornar false (ou não conseguir iniciar o processo filho), o processo atual ainda assim é finalizado, impedindo o relançamento. No Android, spawnProcess(...) explicitamente retorna false, mas em src/framework/core/application.cpp o ramo ANDROID faz exit() (logo não há tentativa de relançamento via spawnProcess). Revisar a lógica para só encerrar o processo atual quando o spawn indicar sucesso (e/ou introduzir fallback/erro no caso de falha).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/core/application.cpp` around lines 183 - 197,
Application::restart() and Application::restartArgs() call
g_platform.spawnProcess(...) and immediately call quick_exit()/exit() without
checking the bool result; change both to call spawnProcess(...) and only call
quick_exit() (or exit()) if spawnProcess returns true. If spawnProcess returns
false, do not terminate the current process; instead log or report the failure
and return so the caller remains running (also handle the ANDROID branch by
avoiding unconditional exit when spawnProcess fails). Update the code paths
around g_platform.spawnProcess, Application::restart, Application::restartArgs,
quick_exit, and exit to implement this conditional behavior.
src/framework/proxy/proxy_client.cpp (1)

427-434: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Entregue o pacote drenado da fila, não o último pacote recebido.

Quando o gap fecha e o while libera mais de um item, o callback recebe packet em todas as iterações. Isso duplica o payload recém-chegado e descarta os pacotes que já estavam bufferizados em m_sendQueue.

💡 Ajuste sugerido
     if (!m_useSocket) {
         while (!m_sendQueue.empty() && m_sendQueue.begin()->first == m_inputPacketId) {
+            const auto& queuedPacket = m_sendQueue.begin()->second;
             m_inputPacketId += 1;
             if (m_recvCallback) {
-                m_recvCallback(packet);
+                m_recvCallback(queuedPacket);
             }
             m_sendQueue.erase(m_sendQueue.begin());
         }
         return;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/proxy/proxy_client.cpp` around lines 427 - 434, O loop que
fecha o gap está chamando m_recvCallback com a variável externa packet em todas
as iterações, duplicando o último pacote e ignorando os itens reais da fila; em
vez disso, atue sobre o item drenado da fila: dentro do while em
proxy_client.cpp use o elemento obtido de m_sendQueue.begin() (por exemplo uma
cópia ou referência chamada queuedPacket) ao atualizar m_inputPacketId, chame
m_recvCallback(queuedPacket) e só então erase(m_sendQueue.begin()), garantindo
que cada pacote bufferizado seja entregue uma vez; mantenha as verificações de
m_useSocket, m_sendQueue, m_inputPacketId e m_recvCallback intactas.
🧹 Nitpick comments (2)
src/client/tile.cpp (1)

994-994: 💤 Low value

Considere manter o argumento de template explícito para maior clareza.

A remoção de <int> de std::abs<int>(...) funciona corretamente, mas o template explícito tornava a intenção mais clara e protegia contra resoluções de sobrecarga inesperadas. Recomenda-se restaurar std::abs<int> para melhor legibilidade.

♻️ Sugestão de reversão
-    if(distance > 0 && std::max<int>(std::abs(m_position.x - playerPos.x), std::abs(m_position.y - playerPos.y)) > distance)
+    if(distance > 0 && std::max<int>(std::abs<int>(m_position.x - playerPos.x), std::abs<int>(m_position.y - playerPos.y)) > distance)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/tile.cpp` at line 994, Restore the explicit template argument on
std::abs to make the intent clear and avoid overload surprises: change the
expression using std::abs in the conditional that compares m_position and
playerPos (the line with if(distance > 0 && std::max<int>(std::abs(m_position.x
- playerPos.x), std::abs(m_position.y - playerPos.y)) > distance)) back to
std::abs<int>(...) for both x and y so the max<int> comparison remains
unambiguous.
src/client/animatedtext.cpp (1)

96-96: 💤 Low value

Considere usar literal float para maior consistência.

A expressão (float)Otc::ANIMATED_TEXT_DURATION / 2.5 funciona corretamente, mas mistura um cast explícito para float com um literal double (2.5). Para maior clareza e consistência de tipos, considere usar 2.5f em vez de 2.5.

♻️ Refatoração sugerida
-    if(m_animationTimer.ticksElapsed() > (float)Otc::ANIMATED_TEXT_DURATION / 2.5)
+    if(m_animationTimer.ticksElapsed() > Otc::ANIMATED_TEXT_DURATION / 2.5f)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/animatedtext.cpp` at line 96, The comparison mixes an explicit
float cast with a double literal; update the right-hand side to use a float
literal (e.g., replace 2.5 with 2.5f) so the expression
(float)Otc::ANIMATED_TEXT_DURATION / 2.5f has consistent float types when used
in the if condition that compares m_animationTimer.ticksElapsed().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/framework/CMakeLists.txt`:
- Line 176: O ramo WASM em src/framework/CMakeLists.txt não fornece os headers
do Asio usados por src/framework/pch.h (que define ASIO_STANDALONE e inclui
<asio.hpp>/<asio/ssl.hpp>), causando falha no preprocessamento; corrija o bloco
if(WASM) para expor os headers do Asio — ou habilite o uso dos headers Boost e
ajuste includes — adicionando a mesma configuração de include/directories usada
quando find_package(asio CONFIG REQUIRED) roda (ou alternadamente definir -s
USE_BOOST_HEADERS=1 e apontar para os include paths de boost/asio), garantindo
que pch.h encontre <asio.hpp> durante a compilação.

In `@src/framework/http/session.cpp`:
- Around line 152-155: Normalize header names and transfer-coding comparisons to
be case-insensitive: when populating or using m_headers (the parsed header map),
convert header names to a canonical form (e.g., lowercase) so lookups like the
Location extraction (currently checking "Location" and "location") work
reliably, and when checking transfer-encoding/transfer-coding values (the parser
that marks chunked when value == "chunked") compare lowercased values or
otherwise perform case-insensitive comparison; update the header-parsing code
that fills m_headers and the places that read Location and
Transfer-Encoding/Transfer-Coding to use the canonical/lowercased keys and
lowercased value comparisons (affecting the Location lookup and the
chunked-detection logic).
- Around line 316-331: The timeout is lost after the first chunk because calling
m_timer.expires_after(...) cancels any pending async_wait; you must re-arm the
wait after resetting the timer. Update the read logic (around m_timer,
m_timer.expires_after, and the async_read_some callers in the session code that
invoke on_read_body) so each new expires_after(...) is followed by a matching
m_timer.async_wait(...) registration (or centralize into a
start_read_with_timeout helper that calls m_timer.expires_after(...) then
m_timer.async_wait(...) and then the appropriate async_read_some on m_ssl or
m_socket), ensuring the timer's handler will cancel the socket/stream on timeout
and that the async_wait is re-registered for every subsequent chunk.
- Around line 91-95: The current verify callback on m_ssl
(m_ssl->set_verify_callback(...)) unconditionally returns true and disables TLS
verification; replace this with proper verification by removing the permissive
lambda and using the platform verifier (keep
m_ssl->set_verify_mode(asio::ssl::verify_peer)) plus either call
m_ssl->set_verify_callback(asio::ssl::rfc2818_verification(hostname)) with the
server hostname, or implement a callback that returns (preverified &&
host-name-check) where you inspect the X509 certificate (e.g., using
X509_check_host or equivalent) to ensure the certificate matches the expected
hostname; update the code paths that construct m_ssl to accept/propagate the
server hostname so rfc2818_verification or host checks can be used.

In `@src/framework/http/session.h`:
- Around line 63-64: A assinatura de HttpSession::on_resolve está errada: o
handler de m_resolver.async_resolve(m_domain, std::to_string(m_port), ...)
recebe asio::ip::tcp::resolver::results_type, não resolver::iterator, então
altere HttpSession::on_resolve para aceitar const
asio::ip::tcp::resolver::results_type& results (ou results_type) e adapte o
corpo correspondente; no .cpp, substitua a lógica que usava
m_socket.async_connect(*iterator, ...) por asio::async_connect(m_socket,
results, /* bind your existing connect handler */) e remova/pare de ajustar
iterator->endpoint().port(m_port) já que a porta/serviço foi passada ao
async_resolve; mantenha nomes existentes (m_resolver, m_socket, on_resolve,
on_connect) ao aplicar a correção.

In `@src/framework/http/websocket.cpp`:
- Around line 104-105: Substitua o uso de um Sec-WebSocket-Key fixo e a simples
busca por "101" por um handshake correto: gere um nonce aleatório por conexão,
base64-encode e escreva-o no header "Sec-WebSocket-Key", calcule o valor
esperado de "Sec-WebSocket-Accept" usando SHA1(nonce +
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") e base64-encode do hash, e ao ler a
resposta verifique explicitamente que o status é 101 e que os headers "Upgrade:
websocket", "Connection: Upgrade" e "Sec-WebSocket-Accept" estão presentes e que
o valor de "Sec-WebSocket-Accept" bate com o esperado; atualize o código que
escreve o header "Sec-WebSocket-Key" e a lógica que atualmente apenas procura a
substring "101" para usar essas verificações robustas.
- Around line 108-114: A vida útil de req_str em
WebsocketSession::do_handshake() não é garantida para a operação assíncrona: em
vez de passar o buffer de uma std::string local para asio::async_write
(m_ssl/m_socket), armazene a requisição como membro (ex.: add m_handshake_req:
std::string e usar asio::buffer(m_handshake_req) ao chamar asio::async_write) ou
crie um std::shared_ptr<std::string> (auto req_ptr =
std::make_shared<std::string>(req.str())) e capture esse req_ptr no handler (use
um lambda que chama on_handshake_sent(shared_from_this(), ec) ou std::bind com
captura do req_ptr) para garantir que os dados permaneçam válidos até
on_handshake_sent ser chamado.
- Around line 302-310: O buffer local `frame` em WebsocketSession::do_write() é
destruído antes de o async_write completar, causando uso-after-free; altere para
alocar o payload como std::shared_ptr<std::vector<uint8_t>> (por exemplo
capturando-o numa variável shared_ptr chamada frame_ptr obtida de
buildWebSocketFrame), passe asio::buffer(*frame_ptr) para asio::async_write
(tanto no ramo m_ssl quanto m_socket) e capture esse frame_ptr no bind/handler
de modo que o recurso só seja liberado no final de WebsocketSession::on_write();
mantenha a lógica atual de desempilhar m_sendQueue dentro de on_write() e
garanta que on_write() libere a captura ao retornar.
- Around line 41-44: The TLS verification is effectively disabled and there are
lifetime/validation bugs: replace the lambda in m_ssl->set_verify_callback(...)
with proper certificate/hostname verification or remove it so verify_peer
enforces CA/hostname checks (use platform verification helpers), and ensure
m_ssl (asio::ssl::stream) performs a real TLS handshake before using WSS; in
do_handshake() validate the server response fully by computing and checking
Sec-WebSocket-Accept against the Sec-WebSocket-Key rather than just searching
for "101" (refer to Sec-WebSocket-Key and Sec-WebSocket-Accept handling), and
fix UAF/UB by ensuring buffers passed to asio::async_write (the local req_str
and local frame vector used in do_handshake() and do_write()) outlive the async
operation — e.g., move them into owned member buffers or use shared_ptr to
heap-allocate and bind them to the async handler so the data remains valid until
the write completes (references: m_ssl, set_verify_callback, do_handshake,
do_write, asio::async_write, asio::buffer).

In `@src/framework/http/websocket.h`:
- Around line 64-65: A assinatura de on_resolve está incorreta:
m_resolver.async_resolve(m_domain, std::to_string(m_port), ...) invoca o handler
com asio::ip::tcp::resolver::results_type, não resolver::iterator; altere a
declaração/definição de on_resolve para receber const
asio::ip::tcp::resolver::results_type& results (em vez de resolver::iterator), e
dentro de on_resolve atualize o uso que fazia
iterator->endpoint()/async_connect(*iterator, ...) para usar results (por
exemplo auto it = results.begin(); use it->endpoint() ou passe results
diretamente para m_socket.async_connect / asio::async_connect conforme a API
usada) assegurando que on_connect mantém assinatura void on_connect(const
asio::error_code& ec).

In `@src/framework/net/connection.cpp`:
- Around line 314-317: A chamada atual a m_socket.remote_endpoint() assume IPv4
e usa ip.address().to_v4().to_ulong(), o que lança em endpoints IPv6; update
getIp() (the code around m_socket.remote_endpoint / ip) to first check
ip.address().is_v4() (and optionally ip.address().is_v4_mapped()), only call
to_v4().to_ulong() for true cases, and provide a safe fallback for IPv6 (e.g.
return 0 or handle mapped-v4 conversion) so the function fails gracefully
instead of throwing.

In `@src/framework/net/packet_player.cpp`:
- Around line 12-23: The custom_unhex function must validate packetHex before
decoding: ensure the input length is even and contains only hex digits, and
detect conversion failures by using strtol's endptr (or equivalent) to verify
each byte token was fully parsed; on any validation or conversion error return
an error/empty optional or throw so callers (e.g., where packetHex is passed at
the call sites around lines 38-39) can abort replay instead of producing
truncated/corrupted packets. Update custom_unhex to perform these checks and
change its return/signature or error handling as needed so callers handle the
failure explicitly.

In `@src/framework/otml/otmlparser.cpp`:
- Around line 192-213: The tokenizer in otmlparser.cpp is dropping quote marks
and backslashes (variables: tokens, current, in_quotes, escaped) so
OTMLNode::value<std::string> never sees a quoted/raw value to unescape; change
the loop so that when a backslash is seen you append the backslash to current
and set escaped for the next char (instead of swallowing it), when an escaped
char is processed append that char (so the sequence stays "\x"), and when
encountering a quote toggle in_quotes but also append the '"' to current (so
quoted boundaries are preserved in the token); keep the comma-splitting behavior
(push_back current on comma when !in_quotes) and only clear current after
pushing.

In `@src/framework/proxy/proxy_client.cpp`:
- Around line 35-41: terminate() currently only closes the socket and cancels
the timer but leaves in-flight async operations (e.g., async_resolve,
async_connect) able to complete and re-mark the proxy connected; update
terminate() and related callback code (callbacks started in the
async_resolve/async_connect flow) to: set m_terminated = true, cancel any
pending resolver and socket operations (call cancel() on the resolver and
shutdown/close the socket with error handling), ensure callbacks check
m_terminated before mutating state or re-adding to g_proxies, and use
weak_ptr/owned self pattern in those callbacks to avoid resurrecting the object
after termination; apply the same fixes to the other similar block(s) referenced
around the 94-136 region so all pending async operations are cancelled and
guarded by m_terminated checks.

In `@src/framework/stdext/net.cpp`:
- Around line 30-38: The code uses
asio::detail::socket_ops::network_to_host_long and host_to_network_long in
ip_to_string and string_to_ip (affecting listSubnetAddresses) which relies on
non-public APIs; replace those calls with standard endianness conversions such
as ntohl/htonl (or a local stdext endian helper / boost::endian equivalent) so
endianness conversion no longer depends on asio::detail. Update ip_to_string to
call ntohl on the IPv4 uint32 before constructing asio::ip::address_v4, and
update string_to_ip to call htonl on address_v4.to_uint() before returning;
ensure any other occurrences (e.g., listSubnetAddresses) are changed the same
way.

In `@src/framework/ui/uitranslator.cpp`:
- Around line 29-30: A entrada em 'aligment' só remove espaços ' ' mas deixa
tabs/newlines/carriage returns, causando fallback para AlignNone/AnchorNone;
antes do mapeamento aplique normalização completa de whitespace (usar
stdext::trim ou remover todos os caracteres onde std::isspace(c) é true), então
chame stdext::tolower(aligment) e continue; refatore as ocorrências em que
'aligment' é processado (mesmo padrão citado nas linhas 54-55) para usar a mesma
normalização usada por translateState e translateAutoFocusPolicy.

In `@src/framework/util/crypt.cpp`:
- Around line 254-261: In Crypt::getCryptKey the code serializes a
platform-dependent std::size_t seed into key via key.assign((const
char*)&seed,...), causing size/endian variability; instead convert the computed
seed into a fixed-size integer (e.g., uint64_t or a fixed 16-byte buffer derived
from the seed), then explicitly serialize it to bytes in a defined byte order
(big-endian or little-endian using shifts/masks) and assign those bytes to key
before passing to xorCrypt; update references to seed in getCryptKey to use the
fixed-size value and ensure xorCrypt always receives the same-length,
order-deterministic key.

In `@vc23/otclient.vcxproj`:
- Line 42: O ficheiro vc23/otclient.vcxproj define PlatformToolset como v145 em
várias entradas; atualiza a documentação e a pipeline para garantir que o Visual
Studio 2026 / Build Tools com MSVC toolset v145 é instalado antes do MSBuild, ou
altere as entradas PlatformToolset (ex.: as tags PlatformToolset que contêm
"v145") para um toolset alternativo suportado pela CI (por exemplo v142) e
documenta o requisito mínimo de build na README/CI config para evitar falhas de
MSBuild.

---

Outside diff comments:
In `@src/framework/CMakeLists.txt`:
- Line 171: Atualize a definição do padrão C++ nos CMakeLists onde aparece
set(CMAKE_CXX_STANDARD 17) para usar 23 (CMAKE_CXX_STANDARD 23) e force o
comportamento consistente adicionando também set(CMAKE_CXX_STANDARD_REQUIRED ON)
e set(CMAKE_CXX_EXTENSIONS OFF) próximo a essas linhas; corrija ambas as
ocorrências do CMakeLists para alinhar com o LanguageStandard usado no projeto
(referência: o símbolo CMAKE_CXX_STANDARD e onde é definido).

In `@src/framework/core/application.cpp`:
- Around line 183-197: Application::restart() and Application::restartArgs()
call g_platform.spawnProcess(...) and immediately call quick_exit()/exit()
without checking the bool result; change both to call spawnProcess(...) and only
call quick_exit() (or exit()) if spawnProcess returns true. If spawnProcess
returns false, do not terminate the current process; instead log or report the
failure and return so the caller remains running (also handle the ANDROID branch
by avoiding unconditional exit when spawnProcess fails). Update the code paths
around g_platform.spawnProcess, Application::restart, Application::restartArgs,
quick_exit, and exit to implement this conditional behavior.

In `@src/framework/proxy/proxy_client.cpp`:
- Around line 427-434: O loop que fecha o gap está chamando m_recvCallback com a
variável externa packet em todas as iterações, duplicando o último pacote e
ignorando os itens reais da fila; em vez disso, atue sobre o item drenado da
fila: dentro do while em proxy_client.cpp use o elemento obtido de
m_sendQueue.begin() (por exemplo uma cópia ou referência chamada queuedPacket)
ao atualizar m_inputPacketId, chame m_recvCallback(queuedPacket) e só então
erase(m_sendQueue.begin()), garantindo que cada pacote bufferizado seja entregue
uma vez; mantenha as verificações de m_useSocket, m_sendQueue, m_inputPacketId e
m_recvCallback intactas.

---

Nitpick comments:
In `@src/client/animatedtext.cpp`:
- Line 96: The comparison mixes an explicit float cast with a double literal;
update the right-hand side to use a float literal (e.g., replace 2.5 with 2.5f)
so the expression (float)Otc::ANIMATED_TEXT_DURATION / 2.5f has consistent float
types when used in the if condition that compares
m_animationTimer.ticksElapsed().

In `@src/client/tile.cpp`:
- Line 994: Restore the explicit template argument on std::abs to make the
intent clear and avoid overload surprises: change the expression using std::abs
in the conditional that compares m_position and playerPos (the line with
if(distance > 0 && std::max<int>(std::abs(m_position.x - playerPos.x),
std::abs(m_position.y - playerPos.y)) > distance)) back to std::abs<int>(...)
for both x and y so the max<int> comparison remains unambiguous.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f9b615d4-4eaa-44ef-9018-af0a0002c08e

📥 Commits

Reviewing files that changed from the base of the PR and between a923e0b and 1954be8.

⛔ Files ignored due to path filters (2)
  • vc17/.vs/otclient/v18/Insiders/Browse.VC.db is excluded by !**/*.db
  • vc17/.vs/otclient/v18/fileList.bin is excluded by !**/*.bin
📒 Files selected for processing (56)
  • src/client/animatedtext.cpp
  • src/client/game.cpp
  • src/client/game.h
  • src/client/minimap.cpp
  • src/client/protocolgame.cpp
  • src/client/protocolgame.h
  • src/client/tile.cpp
  • src/framework/CMakeLists.txt
  • src/framework/cmake/FindBoost.cmake
  • src/framework/core/application.cpp
  • src/framework/core/filestream.cpp
  • src/framework/core/resourcemanager.cpp
  • src/framework/http/http.cpp
  • src/framework/http/http.h
  • src/framework/http/session.cpp
  • src/framework/http/session.h
  • src/framework/http/websocket.cpp
  • src/framework/http/websocket.h
  • src/framework/net/connection.cpp
  • src/framework/net/connection.h
  • src/framework/net/declarations.h
  • src/framework/net/packet_player.cpp
  • src/framework/net/packet_player.h
  • src/framework/net/protocol.cpp
  • src/framework/net/protocol.h
  • src/framework/net/server.cpp
  • src/framework/otml/otmlparser.cpp
  • src/framework/pch.h
  • src/framework/platform/win32platform.cpp
  • src/framework/proxy/proxy.cpp
  • src/framework/proxy/proxy.h
  • src/framework/proxy/proxy_client.cpp
  • src/framework/proxy/proxy_client.h
  • src/framework/sound/streamsoundsource.cpp
  • src/framework/stdext/net.cpp
  • src/framework/stdext/string.cpp
  • src/framework/stdext/uri.cpp
  • src/framework/ui/uitranslator.cpp
  • src/framework/util/crypt.cpp
  • src/framework/util/crypt.h
  • src/framework/xml/tinyxml.cpp
  • vc17/.vs/otclient/FileContentIndex/19a69103-ba74-4359-9b41-6dd0d822002c.vsidx
  • vc17/.vs/otclient/FileContentIndex/77044220-7347-4942-b64b-f8adb883e8d6.vsidx
  • vc17/.vs/otclient/FileContentIndex/9072a3e2-26b5-4363-9356-df58c8ca6583.vsidx
  • vc17/.vs/otclient/v18/.suo
  • vc17/.vs/otclient/v18/DocumentLayout.backup.json
  • vc17/.vs/otclient/v18/DocumentLayout.json
  • vc17/.vs/otclient/v18/Insiders/Browse.VC.db-shm
  • vc17/.vs/otclient/v18/Insiders/Browse.VC.db-wal
  • vc17/otclient.vcxproj.user
  • vc23/debug.props
  • vc23/otclient.sln
  • vc23/otclient.vcxproj
  • vc23/otclient.vcxproj.filters
  • vc23/release.props
  • vc23/settings.props
💤 Files with no reviewable changes (4)
  • src/framework/sound/streamsoundsource.cpp
  • vc17/.vs/otclient/v18/DocumentLayout.backup.json
  • vc17/.vs/otclient/v18/DocumentLayout.json
  • vc17/otclient.vcxproj.user

set(WARNS_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-unused-result")
if(WASM)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNS_FLAGS} ${ARCH_FLAGS} -s USE_ZLIB=1 -s USE_LIBPNG=1 -s USE_SDL=2 -s USE_BOOST_HEADERS=1 -s USE_PTHREADS=1 -O1") # add -Ofast
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNS_FLAGS} ${ARCH_FLAGS} -s USE_ZLIB=1 -s USE_LIBPNG=1 -s USE_SDL=2 -s USE_PTHREADS=1 -O1") # add -Ofast

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf 'Asio includes no código:\n'
rg -n '`#include` <asio' src

printf '\nWiring do build para Asio/Boost/WASM:\n'
rg -n 'USE_BOOST_HEADERS|find_package\(asio|asio::asio|WASM' src/framework/CMakeLists.txt

printf '\nAsio vendorizado no repositório (se não houver hits, o WASM depende de wiring externo):\n'
fd -HI -i 'asio.hpp|asio' .

Repository: Mateuzkl/AstraClient

Length of output: 894


WASM não tem wiring explícito para headers do Asio (falha provável ao compilar)

  • src/framework/pch.h define ASIO_STANDALONE e inclui <asio.hpp> e <asio/ssl.hpp>.
  • Em src/framework/CMakeLists.txt, o find_package(asio CONFIG REQUIRED) só é executado no ramo if(NOT WASM), enquanto o ramo if(WASM) (ex.: set(CMAKE_CXX_FLAGS ... -O1) na linha 176) não adiciona -s USE_BOOST_HEADERS=1 nem inclui diretórios/caminhos para headers do Asio.
  • Sem um include path alternativo, o primeiro TU que incluir pch.h pode falhar no preprocessamento. Ajustar o ramo WASM para fornecer os headers do Asio (ou trocar para boost/asio se a intenção for usar USE_BOOST_HEADERS).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/CMakeLists.txt` at line 176, O ramo WASM em
src/framework/CMakeLists.txt não fornece os headers do Asio usados por
src/framework/pch.h (que define ASIO_STANDALONE e inclui
<asio.hpp>/<asio/ssl.hpp>), causando falha no preprocessamento; corrija o bloco
if(WASM) para expor os headers do Asio — ou habilite o uso dos headers Boost e
ajuste includes — adicionando a mesma configuração de include/directories usada
quando find_package(asio CONFIG REQUIRED) roda (ou alternadamente definir -s
USE_BOOST_HEADERS=1 e apontar para os include paths de boost/asio), garantindo
que pch.h encontre <asio.hpp> durante a compilação.

Comment on lines +91 to 95
m_context = std::make_shared< asio::ssl::context >(asio::ssl::context::tlsv12_client);
m_ssl = std::make_shared<asio::ssl::stream<asio::ip::tcp::socket&>>(m_socket, *m_context);
m_ssl->set_verify_mode(asio::ssl::verify_peer);
m_ssl->set_verify_callback([](bool, asio::ssl::verify_context&) { return true; });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Mostrar o contexto exato ao redor das linhas mencionadas
sed -n '1,140p' src/framework/http/session.cpp | nl -ba | sed -n '70,120p'

# 2) Verificar se existe outra configuração TLS no arquivo (verificações/callbacks/paths)
rg -n "set_verify_mode|set_verify_callback|host_name_verification|set_default_verify_paths|verify_peer|verify_none|verify_context" src/framework/http/session.cpp

# 3) Verificar de onde vem m_domain (ou equivalentes) e se há normalização/uso em outras partes
rg -n "m_domain|domain|host_name" src/framework/http/session.cpp

Repository: Mateuzkl/AstraClient

Length of output: 107


🌐 Web query:

Asio (boost::asio) ssl::host_name_verification usage set_verify_callback verify_context return true when permissive callback implications MITM

💡 Result:

In Boost.Asio, the ssl::verify_callback function is invoked by the underlying OpenSSL implementation to determine whether a peer certificate should be accepted [1][2]. The callback function signature is: bool verify_callback(bool preverified, boost::asio::ssl::verify_context& ctx); The preverified parameter indicates whether the certificate chain passed preliminary verification (e.g., signature checks and trust in the CA) [2]. If you write a custom callback that returns true regardless of the value of preverified (or specifically ignores preverified == false), you effectively bypass OpenSSL's validation mechanisms [2]. This makes your application vulnerable to Man-in-the-Middle (MITM) attacks, as it will accept invalid, expired, self-signed, or untrusted certificates [2][3]. To correctly handle verification: 1. Use boost::asio::ssl::host_name_verification when you need to verify the server's identity against its hostname according to RFC 6125 [4][5]. This is the recommended practice for most HTTPS-like scenarios [5]. 2. If you must implement a custom callback, you should return preverified as the baseline [2][6]. If you need additional checks, return preverified && [your_additional_checks] [2]. 3. Ensure that ssl::verify_peer mode is set on the stream, otherwise the callback may not even be invoked for certificate errors [5]. A permissive callback that always returns true is insecure and should never be used in production environments [2].

Citations:


Corrigir validação TLS: callback de verificação não pode aceitar tudo

O set_verify_callback([](bool, asio::ssl::verify_context&) { return true; }) torna a validação TLS efetivamente permissiva, ignorando o resultado preliminar e aceitando certificados/hostnames inválidos, o que viabiliza MITM mesmo com set_verify_mode(asio::ssl::verify_peer).

💡 Ajuste sugerido
         m_context = std::make_shared< asio::ssl::context >(asio::ssl::context::tlsv12_client);
+        m_context->set_default_verify_paths();
         m_ssl = std::make_shared<asio::ssl::stream<asio::ip::tcp::socket&>>(m_socket, *m_context);
         m_ssl->set_verify_mode(asio::ssl::verify_peer);
-        m_ssl->set_verify_callback([](bool, asio::ssl::verify_context&) { return true; });         
+        m_ssl->set_verify_callback(asio::ssl::host_name_verification(m_domain));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/http/session.cpp` around lines 91 - 95, The current verify
callback on m_ssl (m_ssl->set_verify_callback(...)) unconditionally returns true
and disables TLS verification; replace this with proper verification by removing
the permissive lambda and using the platform verifier (keep
m_ssl->set_verify_mode(asio::ssl::verify_peer)) plus either call
m_ssl->set_verify_callback(asio::ssl::rfc2818_verification(hostname)) with the
server hostname, or implement a callback that returns (preverified &&
host-name-check) where you inspect the X509 certificate (e.g., using
X509_check_host or equivalent) to ensure the certificate matches the expected
hostname; update the code paths that construct m_ssl to accept/propagate the
server hostname so rfc2818_verification or host checks can be used.

Comment on lines +152 to +155
std::string location = m_headers["Location"];
if (location.empty()) {
location = m_headers["location"];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize os headers ao parsear a resposta.

m_headers preserva o case original, mas o redirect só procura "Location"/"location" e o parser só marca chunked quando o valor é exatamente "chunked". Em HTTP, nomes de fields e nomes de transfer-coding são case-insensitive; respostas válidas com casing diferente vão perder redirect ou decodificar o corpo errado. (rfc-editor.org)

Also applies to: 191-213

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/http/session.cpp` around lines 152 - 155, Normalize header
names and transfer-coding comparisons to be case-insensitive: when populating or
using m_headers (the parsed header map), convert header names to a canonical
form (e.g., lowercase) so lookups like the Location extraction (currently
checking "Location" and "location") work reliably, and when checking
transfer-encoding/transfer-coding values (the parser that marks chunked when
value == "chunked") compare lowercased values or otherwise perform
case-insensitive comparison; update the header-parsing code that fills m_headers
and the places that read Location and Transfer-Encoding/Transfer-Coding to use
the canonical/lowercased keys and lowercased value comparisons (affecting the
Location lookup and the chunked-detection logic).

Comment on lines 316 to 331
m_timer.expires_after(std::chrono::seconds(m_timeout));

auto self(shared_from_this());
if (m_ssl) {
boost::beast::http::async_read_some(*m_ssl, m_streambuf, m_response,
std::bind(&HttpSession::on_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
m_ssl->async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
} else {
boost::beast::http::async_read_some(m_socket, m_streambuf, m_response,
std::bind(&HttpSession::on_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
m_socket.async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

O timeout deixa de existir depois do primeiro chunk.

expires_after() cancela o async_wait() pendente. Como este ramo não registra outro async_wait, a transferência pode ficar presa indefinidamente após qualquer progresso parcial. (think-async.com)

💡 Ajuste sugerido
     m_timer.expires_after(std::chrono::seconds(m_timeout));
+    m_timer.async_wait(std::bind(&HttpSession::onTimeout, shared_from_this(), std::placeholders::_1));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
m_timer.expires_after(std::chrono::seconds(m_timeout));
auto self(shared_from_this());
if (m_ssl) {
boost::beast::http::async_read_some(*m_ssl, m_streambuf, m_response,
std::bind(&HttpSession::on_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
m_ssl->async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
} else {
boost::beast::http::async_read_some(m_socket, m_streambuf, m_response,
std::bind(&HttpSession::on_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
m_socket.async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
}
m_timer.expires_after(std::chrono::seconds(m_timeout));
m_timer.async_wait(std::bind(&HttpSession::onTimeout, shared_from_this(), std::placeholders::_1));
auto self(shared_from_this());
if (m_ssl) {
m_ssl->async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
} else {
m_socket.async_read_some(m_streambuf.prepare(16384),
[this, self](const asio::error_code& ec, size_t bytes) {
m_streambuf.commit(bytes);
on_read_body(ec, bytes);
});
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/http/session.cpp` around lines 316 - 331, The timeout is lost
after the first chunk because calling m_timer.expires_after(...) cancels any
pending async_wait; you must re-arm the wait after resetting the timer. Update
the read logic (around m_timer, m_timer.expires_after, and the async_read_some
callers in the session code that invoke on_read_body) so each new
expires_after(...) is followed by a matching m_timer.async_wait(...)
registration (or centralize into a start_read_with_timeout helper that calls
m_timer.expires_after(...) then m_timer.async_wait(...) and then the appropriate
async_read_some on m_ssl or m_socket), ensuring the timer's handler will cancel
the socket/stream on timeout and that the async_wait is re-registered for every
subsequent chunk.

Comment on lines +63 to +64
void on_resolve(const asio::error_code& ec, asio::ip::tcp::resolver::iterator iterator);
void on_connect(const asio::error_code& ec);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Localizar o arquivo e ler o trecho das linhas citadas
ls -la src/framework/http || true
nl -ba src/framework/http/session.h | sed -n '1,120p'

# 2) Buscar por declarações/definições de on_resolve/on_connect e uso de async_resolve/async_connect
rg -n "on_resolve\s*\(|on_connect\s*\(|async_resolve\s*\(|async_connect\s*\(" src/framework/http -S

# 3) Tentar localizar a implementação em .cpp/.cc/.ipp/.inl correlatos
# (sem assumir caminho exato: buscar pelo nome das funções no repo)
rg -n "void\s+.*on_resolve\s*\(" -S .

# 4) Inspecionar o corpo do on_resolve (se encontrado) e o uso do resultado/iterator
# Pegando os contextos ao redor das match lines
matches=$(rg -n "on_resolve\s*\(" -S . || true)
echo "$matches" | head -n 50

# 5) Ler ao redor dos usos encontrados
for f in $(echo "$matches" | awk -F: '{print $1}' | sort -u); do
  echo "---- $f (relevante) ----"
  # mostra alguns contextos perto do primeiro match
  ln=$(echo "$matches" | awk -F: -v file="$f" '$1==file{print $2; exit}')
  if [[ -n "${ln:-}" ]]; then
    start=$((ln-30)); end=$((ln+80));
    if (( start<1 )); then start=1; fi
    nl -ba "$f" | sed -n "${start},${end}p"
  else
    nl -ba "$f" | head -n 160
  fi
done

Repository: Mateuzkl/AstraClient

Length of output: 671


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Listar diretório
ls -la src/framework/http

# 2) Mostrar session.h com line numbers via awk
awk '{printf "%6d\t%s\n", NR, $0}' src/framework/http/session.h | sed -n '1,140p'

# 3) Buscar usos relevantes em session.h/cpp
rg -n "on_resolve\s*\(|async_resolve\s*\(|async_connect\s*\(" src/framework/http/session.h src/framework/http/session.cpp -S || true

# 4) Mostrar definição/implementação de on_resolve em session.cpp (se existir)
rg -n "on_resolve\s*\(" src/framework/http/session.cpp -S || true

# 5) Mostrar um trecho maior de session.cpp para capturar o contrato completo
awk '{printf "%6d\t%s\n", NR, $0}' src/framework/http/session.cpp | sed -n '1,240p'

Repository: Mateuzkl/AstraClient

Length of output: 14756


🌐 Web query:

Asio standalone ip::tcp::resolver::async_resolve(host, service, handler) handler signature iterator results_type

💡 Result:

In Asio (both the Boost and standalone versions), the completion handler for ip::tcp::resolver::async_resolve must have the following signature [1][2][3]: void handler( const boost::system::error_code& error, boost::asio::ip::tcp::resolver::results_type results); The completion signature is defined as void(boost::system::error_code, results_type) [1][3]. The results_type (boost::asio::ip::tcp::resolver::results_type) is a typedef for boost::asio::ip::basic_resolver_resultsboost::asio::ip::tcp [4][5]. It represents a range over the resolved endpoints and provides iterator access to the individual resolution entries [4][5]. A successful resolution operation is guaranteed to pass a non-empty range to the handler [1][3].

Citations:


Corrigir o tipo do callback de on_resolve (iterator vs results_type)

A assinatura atual de HttpSession::on_resolve usa asio::ip::tcp::resolver::iterator, mas o m_resolver.async_resolve(m_domain, std::to_string(m_port), ...) (overload com 3 argumentos) completa o handler com asio::ip::tcp::resolver::results_type. Isso gera quebra na compilação e impede conectar varrendo todos os endpoints resolvidos.

💡 Ajuste sugerido
-    void on_resolve(const asio::error_code& ec, asio::ip::tcp::resolver::iterator iterator);
+    void on_resolve(const asio::error_code& ec, asio::ip::tcp::resolver::results_type results);

No .cpp, troque o uso atual de m_socket.async_connect(*iterator, ...) por asio::async_connect(m_socket, results, ...) (e remova/ajuste o iterator->endpoint().port(m_port) já que você está passando service/porta em async_resolve).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void on_resolve(const asio::error_code& ec, asio::ip::tcp::resolver::iterator iterator);
void on_connect(const asio::error_code& ec);
void on_resolve(const asio::error_code& ec, asio::ip::tcp::resolver::results_type results);
void on_connect(const asio::error_code& ec);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/http/session.h` around lines 63 - 64, A assinatura de
HttpSession::on_resolve está errada: o handler de
m_resolver.async_resolve(m_domain, std::to_string(m_port), ...) recebe
asio::ip::tcp::resolver::results_type, não resolver::iterator, então altere
HttpSession::on_resolve para aceitar const
asio::ip::tcp::resolver::results_type& results (ou results_type) e adapte o
corpo correspondente; no .cpp, substitua a lógica que usava
m_socket.async_connect(*iterator, ...) por asio::async_connect(m_socket,
results, /* bind your existing connect handler */) e remova/pare de ajustar
iterator->endpoint().port(m_port) já que a porta/serviço foi passada ao
async_resolve; mantenha nomes existentes (m_resolver, m_socket, on_resolve,
on_connect) ao aplicar a correção.

Comment on lines 35 to 41
auto self(shared_from_this());
boost::asio::post(m_io, [&, self] {
asio::post(m_io, [&, self] {
g_proxies.erase(self);
disconnect();
boost::system::error_code ec;
asio::error_code ec;
m_timer.cancel(ec);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Cancele operações pendentes ao encerrar o proxy.

terminate() só fecha o socket e cancela o timer. Se um async_resolve ou async_connect já estiver em voo, os callbacks aqui ainda podem completar depois de m_terminated = true e recolocar o proxy em estado conectado, reabrindo tráfego após a remoção de g_proxies.

💡 Ajuste sugerido
 void Proxy::terminate()
 {
     if (m_terminated)
         return;
     m_terminated = true;
@@
     auto self(shared_from_this());
     asio::post(m_io, [&, self] {
         g_proxies.erase(self);
+        asio::error_code resolverEc;
+        m_resolver.cancel(resolverEc);
         disconnect();
         asio::error_code ec;
         m_timer.cancel(ec);
     });
 }
@@
     m_resolver.async_resolve(m_host, "http", [self](const asio::error_code& ec,
                                                     asio::ip::tcp::resolver::results_type results) {
+        if (self->m_terminated)
+            return;
         auto endpoint = asio::ip::tcp::endpoint();
@@
         self->m_socket = asio::ip::tcp::socket(self->m_io);
         self->m_lastPingSent = std::chrono::high_resolution_clock::now(); // used for async_connect timeout
         self->m_socket.async_connect(endpoint, [self, endpoint](const asio::error_code& ec) {
+            if (self->m_terminated)
+                return;
             if (ec) {
                 self->m_state = STATE_NOT_CONNECTED;
                 return;
             }

Also applies to: 94-136

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/proxy/proxy_client.cpp` around lines 35 - 41, terminate()
currently only closes the socket and cancels the timer but leaves in-flight
async operations (e.g., async_resolve, async_connect) able to complete and
re-mark the proxy connected; update terminate() and related callback code
(callbacks started in the async_resolve/async_connect flow) to: set m_terminated
= true, cancel any pending resolver and socket operations (call cancel() on the
resolver and shutdown/close the socket with error handling), ensure callbacks
check m_terminated before mutating state or re-adding to g_proxies, and use
weak_ptr/owned self pattern in those callbacks to avoid resurrecting the object
after termination; apply the same fixes to the other similar block(s) referenced
around the 94-136 region so all pending async operations are cancelled and
guarded by m_terminated checks.

Comment on lines +30 to +38
ip = asio::detail::socket_ops::network_to_host_long(ip);
asio::ip::address_v4 address_v4 = asio::ip::address_v4(ip);
return address_v4.to_string();
}

uint32 string_to_ip(const std::string& string)
{
boost::asio::ip::address_v4 address_v4 = boost::asio::ip::address_v4::from_string(string);
return boost::asio::detail::socket_ops::host_to_network_long(address_v4.to_ulong());
asio::ip::address_v4 address_v4 = asio::ip::make_address_v4(string);
return asio::detail::socket_ops::host_to_network_long(address_v4.to_uint());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is asio::detail::socket_ops::host_to_network_long/network_to_host_long part of Asio's public stable API, and what public alternative is recommended for byte-order conversion in standalone Asio?

💡 Result:

The functions asio::detail::socket_ops::host_to_network_long and network_to_host_long are not part of Asio's public, stable API [1][2]. As indicated by their placement within the detail namespace, they are internal implementation details used by Asio and are subject to change or removal without notice [1][3][2]. You should not rely on them in your own code [3]. For standalone Asio, or when using Asio with Boost, the recommended alternatives for byte-order conversion are: 1. Standard POSIX/Socket functions: You can use the standard C socket API functions, which are widely available on most platforms: ntohl, htonl, ntohs, and htons (typically found in <arpa/inet.h> on POSIX or <winsock2.h> on Windows) [4]. 2. Boost.Endian library: If you are using Asio in a Boost-enabled project, the Boost.Endian library is the preferred, robust way to handle byte-order conversions [5][4]. It provides clean, type-safe interfaces, including endian-specific integer types (e.g., boost::endian::big_int32_t, boost::endian::little_int32_t) and conversion functions [6][7][8][5]. 3. C++23 standard library: If your environment supports C++23, you can use the <bit> header, which provides std::byteswap for byte reversal, which is the foundational operation needed to implement endianness conversions manually if a full library is not desired.

Citations:


Evite asio::detail::socket_ops para conversão de endianness

asio::detail::socket_ops::host_to_network_long/network_to_host_long ficam no namespace detail, ou seja, não fazem parte de API pública/estável; isso pode quebrar com atualizações e afetar a superfície exposta para Lua via ip_to_string, string_to_ip e listSubnetAddresses em src/framework/luafunctions.cpp (usando os helpers de src/framework/stdext/net.cpp:30-38). Prefira conversão via htonl/ntohl (ou htons/ntohs se aplicável) e/ou um helper local de endianness em stdext (alternativa: boost::endian se estiver no ecossistema Boost).

Also applies to: 47-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/stdext/net.cpp` around lines 30 - 38, The code uses
asio::detail::socket_ops::network_to_host_long and host_to_network_long in
ip_to_string and string_to_ip (affecting listSubnetAddresses) which relies on
non-public APIs; replace those calls with standard endianness conversions such
as ntohl/htonl (or a local stdext endian helper / boost::endian equivalent) so
endianness conversion no longer depends on asio::detail. Update ip_to_string to
call ntohl on the IPv4 uint32 before constructing asio::ip::address_v4, and
update string_to_ip to call htonl on address_v4.to_uint() before returning;
ensure any other occurrences (e.g., listSubnetAddresses) are changed the same
way.

Comment on lines +29 to +30
stdext::tolower(aligment);
aligment.erase(std::remove(aligment.begin(), aligment.end(), ' '), aligment.end());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize toda a whitespace antes do mapeamento.

Aqui só o caractere ' ' é removido. Entradas com \t, \r ou \n continuam no token e passam a cair em AlignNone/AnchorNone, enquanto translateState e translateAutoFocusPolicy já tratam esse caso com stdext::trim.

💡 Ajuste sugerido
 Fw::AlignmentFlag Fw::translateAlignment(std::string aligment)
 {
     stdext::tolower(aligment);
+    stdext::trim(aligment);
     aligment.erase(std::remove(aligment.begin(), aligment.end(), ' '), aligment.end());
     if(aligment == "topleft")
         return Fw::AlignTopLeft;
@@
 Fw::AnchorEdge Fw::translateAnchorEdge(std::string anchorEdge)
 {
     stdext::tolower(anchorEdge);
+    stdext::trim(anchorEdge);
     anchorEdge.erase(std::remove(anchorEdge.begin(), anchorEdge.end(), ' '), anchorEdge.end());
     if(anchorEdge == "left")
         return Fw::AnchorLeft;

Also applies to: 54-55

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/ui/uitranslator.cpp` around lines 29 - 30, A entrada em
'aligment' só remove espaços ' ' mas deixa tabs/newlines/carriage returns,
causando fallback para AlignNone/AnchorNone; antes do mapeamento aplique
normalização completa de whitespace (usar stdext::trim ou remover todos os
caracteres onde std::isspace(c) é true), então chame stdext::tolower(aligment) e
continue; refatore as ocorrências em que 'aligment' é processado (mesmo padrão
citado nas linhas 54-55) para usar a mesma normalização usada por translateState
e translateAutoFocusPolicy.

Comment on lines +254 to +261
std::size_t seed = 0;
for (uint8_t b : u) {
std::size_t to_hash = b;
seed ^= to_hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

std::string key;
key.assign((const char *)&hash, sizeof(hash));
key.assign((const char *)&seed, sizeof(seed));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
base="$(git merge-base HEAD origin/main 2>/dev/null || git rev-parse HEAD~1)"

echo "=== Diff do getCryptKey ==="
git diff --unified=40 "$base"...HEAD -- src/framework/util/crypt.cpp | sed -n '/std::string Crypt::getCryptKey/,/return key;/p'

echo
echo "=== Call sites relevantes ==="
rg -n -C2 '\b(getMachineUUID|setMachineUUID|encrypt\(|decrypt\()' src

Repository: Mateuzkl/AstraClient

Length of output: 3539


Evite serializar std::size_t como chave em Crypt::getCryptKey
Em src/framework/util/crypt.cpp (lin. 254-261), a chave é montada com key.assign((const char*)&seed, sizeof(seed)) onde seed é std::size_t; isso varia com sizeof(size_t) e endianness entre plataformas/builds, quebrando compatibilidade das mensagens criptografadas (e do decrypter).
Derive a chave em um tamanho fixo (ex.: uint64_t/16 bytes) e serialize em uma ordem de bytes definida antes de usar no xorCrypt.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/framework/util/crypt.cpp` around lines 254 - 261, In Crypt::getCryptKey
the code serializes a platform-dependent std::size_t seed into key via
key.assign((const char*)&seed,...), causing size/endian variability; instead
convert the computed seed into a fixed-size integer (e.g., uint64_t or a fixed
16-byte buffer derived from the seed), then explicitly serialize it to bytes in
a defined byte order (big-endian or little-endian using shifts/masks) and assign
those bytes to key before passing to xorCrypt; update references to seed in
getCryptKey to use the fixed-size value and ensure xorCrypt always receives the
same-length, order-deterministic key.

Comment thread vc23/otclient.vcxproj
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<PlatformToolset>v145</PlatformToolset>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Qual é o valor válido de <PlatformToolset> para a versão mais recente do Visual Studio/Build Tools e qual versão mínima oferece suporte a v145? Se v145não for um toolset amplamente disponível, qual é o valor correto suportado para projetos.vcxproj com C++23?

💡 Result:

O valor válido e mais recente de PlatformToolset para o Visual Studio 2026 é v145 [1][2][3]. Sobre o suporte ao v145: Este toolset foi introduzido especificamente com o Visual Studio 2026 (versão 18.0) [1][2]. Não é um toolset legado disponível em versões anteriores do Visual Studio, mas sim o sucessor direto do v143 (utilizado no Visual Studio 2022) [3]. Portanto, a versão mínima do Visual Studio que oferece suporte ao v145 é o Visual Studio 2026 [1][2]. Sobre C++23 e.vcxproj: O valor v145 é o valor correto e suportado para projetos.vcxproj que visam utilizar funcionalidades de C++23 no Visual Studio 2026 [1]. Para habilitar o suporte ao padrão C++23, além de definir o PlatformToolset como v145, você deve configurar a propriedade de idioma para /std:c++23preview ou, para as funcionalidades mais recentes, utilizar /std:c++latest nas configurações do seu projeto [1][4]. Resumo: - Toolset atual: v145 [1][3]. - Suporte mínimo: Visual Studio 2026 [1][2]. - Para C++23: Utilize v145 em conjunto com a flag /std:c++23preview ou /std:c++latest [1].

Citations:


🌐 Web query:

PlatformToolset v145 Visual Studio 2026 msbuild property documentation

💡 Result:

The PlatformToolset v145 is the default C++ toolset for Visual Studio 2026 (version 18.0) [1][2][3]. The PlatformToolset is an MSBuild property that determines which Microsoft C++ (MSVC) toolset—including the compiler (cl.exe), linker (link.exe), and standard libraries—is used to build a C++ project [4][5][6]. Setting this property allows you to target specific versions of the MSVC build tools regardless of the host Visual Studio version installed, provided the chosen toolset is installed on the machine [4][3]. Key characteristics of the v145 toolset include: - Visual Studio Version: Introduced with Visual Studio 2026 (18.0) [1][2][3]. - MSVC Build Tools Version: Corresponds to version 14.50 [1][2][3]. - Project File Usage: In.vcxproj files, the property is defined within a PropertyGroup, typically labeled "Globals" [7]: v145 - Command Line Usage: You can override the toolset during an MSBuild invocation using the command-line switch [4]: msbuild myProject.vcxproj /p:PlatformToolset=v145 The v145 toolset continues the established naming convention and maintains binary compatibility with previous versions (v140, v141, v142, and v143), allowing for interoperability between code built with these different toolsets [5][3][6]. It is recommended to use the Property Manager in Visual Studio to retarget projects to the latest toolset or to manually edit the.vcxproj file if managing builds outside the IDE [2][5][8].

Citations:


Ajustar CI/documentação para garantir o availability do PlatformToolset v145
O PlatformToolset v145 foi introduzido no Visual Studio 2026 (MSVC 14.50) e só funciona quando o toolset v145 está instalado; com VS/Build Tools mais antigos, o MSBuild falha antes mesmo de compilar. Como vc23/otclient.vcxproj já fixa PlatformToolset=v145 (linhas 42, 51, 60, 78 e 87), alinhar a pipeline e requisitos mínimos para instalar o VS 2026 Build Tools (ou definir um toolset alternativo suportado).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vc23/otclient.vcxproj` at line 42, O ficheiro vc23/otclient.vcxproj define
PlatformToolset como v145 em várias entradas; atualiza a documentação e a
pipeline para garantir que o Visual Studio 2026 / Build Tools com MSVC toolset
v145 é instalado antes do MSBuild, ou altere as entradas PlatformToolset (ex.:
as tags PlatformToolset que contêm "v145") para um toolset alternativo suportado
pela CI (por exemplo v142) e documenta o requisito mínimo de build na README/CI
config para evitar falhas de MSBuild.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant