mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-04 00:13:51 +00:00
Add authenticator opcode support + auth_probe tool
This commit is contained in:
parent
3a84fece7a
commit
d87ba314c1
8 changed files with 188 additions and 15 deletions
|
|
@ -101,7 +101,7 @@ void AuthHandler::authenticate(const std::string& user, const std::string& pass,
|
|||
|
||||
username = user;
|
||||
password = pass;
|
||||
pendingPin_ = pin;
|
||||
pendingSecurityCode_ = pin;
|
||||
securityFlags_ = 0;
|
||||
pinGridSeed_ = 0;
|
||||
pinServerSalt_ = {};
|
||||
|
|
@ -135,7 +135,7 @@ void AuthHandler::authenticateWithHash(const std::string& user, const std::vecto
|
|||
|
||||
username = user;
|
||||
password.clear();
|
||||
pendingPin_ = pin;
|
||||
pendingSecurityCode_ = pin;
|
||||
securityFlags_ = 0;
|
||||
pinGridSeed_ = 0;
|
||||
pinServerSalt_ = {};
|
||||
|
|
@ -203,9 +203,9 @@ void AuthHandler::handleLogonChallengeResponse(network::Packet& packet) {
|
|||
|
||||
setState(AuthState::CHALLENGE_RECEIVED);
|
||||
|
||||
// If PIN is required, wait for user input.
|
||||
if ((securityFlags_ & 0x01) && pendingPin_.empty()) {
|
||||
setState(AuthState::PIN_REQUIRED);
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ void AuthHandler::sendLogonProof() {
|
|||
|
||||
if (securityFlags_ & 0x01) {
|
||||
try {
|
||||
PinProof proof = computePinProof(pendingPin_, pinGridSeed_, pinServerSalt_);
|
||||
PinProof proof = computePinProof(pendingSecurityCode_, pinGridSeed_, pinServerSalt_);
|
||||
pinClientSalt = proof.clientSalt;
|
||||
pinHash = proof.hash;
|
||||
pinClientSaltPtr = &pinClientSalt;
|
||||
|
|
@ -239,13 +239,25 @@ void AuthHandler::sendLogonProof() {
|
|||
auto packet = LogonProofPacket::build(A, M1, securityFlags_, pinClientSaltPtr, pinHashPtr);
|
||||
socket->send(packet);
|
||||
|
||||
if (securityFlags_ & 0x04) {
|
||||
// TrinityCore-style Google Authenticator token: send immediately after proof.
|
||||
// Token is typically 6 digits.
|
||||
const std::string token = pendingSecurityCode_;
|
||||
auto tokPkt = AuthenticatorTokenPacket::build(token);
|
||||
socket->send(tokPkt);
|
||||
}
|
||||
|
||||
setState(AuthState::PROOF_SENT);
|
||||
}
|
||||
|
||||
void AuthHandler::submitPin(const std::string& pin) {
|
||||
pendingPin_ = pin;
|
||||
// If we're waiting on a PIN, continue immediately.
|
||||
if (state == AuthState::PIN_REQUIRED) {
|
||||
submitSecurityCode(pin);
|
||||
}
|
||||
|
||||
void AuthHandler::submitSecurityCode(const std::string& code) {
|
||||
pendingSecurityCode_ = code;
|
||||
// If we're waiting on a security code, continue immediately.
|
||||
if (state == AuthState::PIN_REQUIRED || state == AuthState::AUTHENTICATOR_REQUIRED) {
|
||||
sendLogonProof();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,10 @@ bool LogonChallengeResponseParser::parse(network::Packet& packet, LogonChallenge
|
|||
response.pinSalt[i] = packet.readUInt8();
|
||||
}
|
||||
}
|
||||
if (response.securityFlags & 0x04) {
|
||||
// Authenticator required (TrinityCore): u8 requiredFlag (usually 1)
|
||||
response.authenticatorRequired = packet.readUInt8();
|
||||
}
|
||||
|
||||
LOG_DEBUG("Parsed LOGON_CHALLENGE response:");
|
||||
LOG_DEBUG(" B size: ", response.B.size(), " bytes");
|
||||
|
|
@ -210,6 +214,17 @@ network::Packet LogonProofPacket::build(const std::vector<uint8_t>& A,
|
|||
return packet;
|
||||
}
|
||||
|
||||
network::Packet AuthenticatorTokenPacket::build(const std::string& token) {
|
||||
network::Packet packet(static_cast<uint16_t>(AuthOpcode::AUTHENTICATOR));
|
||||
// TrinityCore expects: u8 len + ascii token bytes (not null-terminated)
|
||||
uint8_t len = static_cast<uint8_t>(std::min<size_t>(255, token.size()));
|
||||
packet.writeUInt8(len);
|
||||
if (len > 0) {
|
||||
packet.writeBytes(reinterpret_cast<const uint8_t*>(token.data()), len);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
bool LogonProofResponseParser::parse(network::Packet& packet, LogonProofResponse& response) {
|
||||
// Note: opcode byte already consumed by handlePacket()
|
||||
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
|
|||
// Connect button
|
||||
if (authenticating) {
|
||||
auto state = authHandler.getState();
|
||||
if (state != auth::AuthState::PIN_REQUIRED) {
|
||||
if (state != auth::AuthState::PIN_REQUIRED && state != auth::AuthState::AUTHENTICATOR_REQUIRED) {
|
||||
pinAutoSubmitted_ = false;
|
||||
authTimer += ImGui::GetIO().DeltaTime;
|
||||
|
||||
|
|
@ -385,8 +385,10 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
|
|||
for (size_t i = 0; i < len; ++i) {
|
||||
if (pinCode[i] < '0' || pinCode[i] > '9') { digitsOnly = false; break; }
|
||||
}
|
||||
if (digitsOnly && len >= 4 && len <= 10) {
|
||||
authHandler.submitPin(pinCode);
|
||||
// Auto-submit if the user prefilled a plausible code.
|
||||
// PIN-grid: 4-10 digits. Authenticator (TOTP): typically 6 digits.
|
||||
if (digitsOnly && ((len >= 4 && len <= 10) || len == 6)) {
|
||||
authHandler.submitSecurityCode(pinCode);
|
||||
pinCode[0] = '\0';
|
||||
pinAutoSubmitted_ = true;
|
||||
}
|
||||
|
|
@ -394,7 +396,7 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
|
|||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Submit 2FA/PIN")) {
|
||||
authHandler.submitPin(pinCode);
|
||||
authHandler.submitSecurityCode(pinCode);
|
||||
// Don't keep the code around longer than needed.
|
||||
pinCode[0] = '\0';
|
||||
pinAutoSubmitted_ = true;
|
||||
|
|
@ -429,7 +431,8 @@ void AuthScreen::render(auth::AuthHandler& authHandler) {
|
|||
setStatus("Authentication failed", true);
|
||||
}
|
||||
authenticating = false;
|
||||
} else if (state != auth::AuthState::PIN_REQUIRED && authTimer >= AUTH_TIMEOUT) {
|
||||
} else if (state != auth::AuthState::PIN_REQUIRED && state != auth::AuthState::AUTHENTICATOR_REQUIRED
|
||||
&& authTimer >= AUTH_TIMEOUT) {
|
||||
setStatus("Connection timed out - server did not respond", true);
|
||||
authenticating = false;
|
||||
authHandler.disconnect();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue