refactor: name auth security flags, log JSON parse failures

- auth_handler: define kSecurityFlagPin/MatrixCard/Authenticator
  constants (0x01/0x02/0x04) with why-comment explaining WoW login
  challenge securityFlags byte, replace all bare hex literals
- expansion_profile: log warning on jsonInt() parse failure instead
  of silently returning default — makes malformed expansion.json
  diagnosable without debugger
This commit is contained in:
Kelsi 2026-03-30 14:43:50 -07:00
parent 74f0ba010a
commit a940859e6a
2 changed files with 22 additions and 9 deletions

View file

@ -13,6 +13,12 @@
namespace wowee {
namespace auth {
// WoW login security flags (CMD_AUTH_LOGON_CHALLENGE response, securityFlags byte).
// Multiple flags can be set simultaneously; the client must satisfy all of them.
constexpr uint8_t kSecurityFlagPin = 0x01; // PIN grid challenge
constexpr uint8_t kSecurityFlagMatrixCard = 0x02; // Matrix card (unused by most servers)
constexpr uint8_t kSecurityFlagAuthenticator = 0x04; // TOTP authenticator token
AuthHandler::AuthHandler() {
LOG_DEBUG("AuthHandler created");
}
@ -196,9 +202,9 @@ void AuthHandler::handleLogonChallengeResponse(network::Packet& packet) {
if (response.securityFlags != 0) {
LOG_WARNING("Server sent security flags: 0x", std::hex, static_cast<int>(response.securityFlags), std::dec);
if (response.securityFlags & 0x01) LOG_WARNING(" PIN required");
if (response.securityFlags & 0x02) LOG_WARNING(" Matrix card required (not supported)");
if (response.securityFlags & 0x04) LOG_WARNING(" Authenticator required (not supported)");
if (response.securityFlags & kSecurityFlagPin) LOG_WARNING(" PIN required");
if (response.securityFlags & kSecurityFlagMatrixCard) LOG_WARNING(" Matrix card required (not supported)");
if (response.securityFlags & kSecurityFlagAuthenticator) LOG_WARNING(" Authenticator required (not supported)");
}
LOG_INFO("Challenge: N=", response.N.size(), "B g=", response.g.size(), "B salt=",
@ -209,7 +215,7 @@ void AuthHandler::handleLogonChallengeResponse(network::Packet& packet) {
securityFlags_ = response.securityFlags;
checksumSalt_ = response.checksumSalt;
if (securityFlags_ & 0x01) {
if (securityFlags_ & kSecurityFlagPin) {
pinGridSeed_ = response.pinGridSeed;
pinServerSalt_ = response.pinSalt;
}
@ -217,8 +223,8 @@ void AuthHandler::handleLogonChallengeResponse(network::Packet& packet) {
setState(AuthState::CHALLENGE_RECEIVED);
// If a security code is required, wait for user input.
if (((securityFlags_ & 0x04) || (securityFlags_ & 0x01)) && pendingSecurityCode_.empty()) {
setState((securityFlags_ & 0x04) ? AuthState::AUTHENTICATOR_REQUIRED : AuthState::PIN_REQUIRED);
if (((securityFlags_ & kSecurityFlagAuthenticator) || (securityFlags_ & kSecurityFlagPin)) && pendingSecurityCode_.empty()) {
setState((securityFlags_ & kSecurityFlagAuthenticator) ? AuthState::AUTHENTICATOR_REQUIRED : AuthState::PIN_REQUIRED);
return;
}
@ -238,7 +244,7 @@ void AuthHandler::sendLogonProof() {
std::array<uint8_t, 20> crcHash{};
const std::array<uint8_t, 20>* crcHashPtr = nullptr;
if (securityFlags_ & 0x01) {
if (securityFlags_ & kSecurityFlagPin) {
try {
PinProof proof = computePinProof(pendingSecurityCode_, pinGridSeed_, pinServerSalt_);
pinClientSalt = proof.clientSalt;
@ -299,7 +305,7 @@ void AuthHandler::sendLogonProof() {
auto packet = LogonProofPacket::build(A, M1, securityFlags_, crcHashPtr, pinClientSaltPtr, pinHashPtr);
socket->send(packet);
if (securityFlags_ & 0x04) {
if (securityFlags_ & kSecurityFlagAuthenticator) {
// TrinityCore-style Google Authenticator token: send immediately after proof.
const std::string token = pendingSecurityCode_;
auto tokPkt = AuthenticatorTokenPacket::build(token);

View file

@ -58,7 +58,14 @@ std::string jsonValue(const std::string& json, const std::string& key) {
int jsonInt(const std::string& json, const std::string& key, int def = 0) {
std::string v = jsonValue(json, key);
if (v.empty()) return def;
try { return std::stoi(v); } catch (...) { return def; }
try {
return std::stoi(v);
} catch (...) {
// Non-numeric value for an integer field — fall back to default rather than
// crashing, but log it so malformed expansion.json files are diagnosable.
wowee::core::Logger::getInstance().warning("jsonInt: failed to parse '", key, "' value '", v, "', using default ", def);
return def;
}
}
std::vector<uint32_t> jsonUintArray(const std::string& json, const std::string& key) {