/* * WALogin.cpp * * Created on: 26/06/2012 * Author: Antonio */ #include "WALogin.h" #include "ByteArray.h" #include "ProtocolTreeNode.h" #include "WAException.h" #include #include #include #include #include "../common.h" // #TODO Remove Miranda-dependency using namespace Utilities; const std::string WALogin::NONCE_KEY = "nonce=\""; WALogin::WALogin(WAConnection* connection, const std::string& password) { m_pConnection = connection; this->password = password; this->account_kind = -1; this->expire_date = 0L; } std::vector WALogin::login(const std::vector& authBlob) { m_pConnection->out->streamStart(m_pConnection->domain, m_pConnection->resource); m_pConnection->logData("sent stream start"); sendFeatures(); m_pConnection->logData("sent features"); sendAuth(authBlob); m_pConnection->logData("send auth, auth blob size %d", authBlob.size()); m_pConnection->in->streamStart(); m_pConnection->logData("read stream start"); return this->readFeaturesUntilChallengeOrSuccess(); } void WALogin::sendResponse(const std::vector& challengeData) { std::vector* authBlob = this->getAuthBlob(challengeData); m_pConnection->out->write(ProtocolTreeNode("response", authBlob)); } void WALogin::sendFeatures() { ProtocolTreeNode* child = new ProtocolTreeNode("receipt_acks"); std::vector* children = new std::vector(); children->push_back(child); ProtocolTreeNode* pictureChild = new ProtocolTreeNode("w:profile:picture") << XATTR("type", "all"); children->push_back(pictureChild); m_pConnection->out->write(ProtocolTreeNode("stream:features", NULL, children), true); } void WALogin::sendAuth(const std::vector& existingChallenge) { std::vector* data = NULL; if (!existingChallenge.empty()) data = this->getAuthBlob(existingChallenge); m_pConnection->out->write(ProtocolTreeNode("auth", data) << XATTR("mechanism", "WAUTH-2") << XATTR("user", m_pConnection->user), true); } std::vector* WALogin::getAuthBlob(const std::vector& nonce) { unsigned char out[4*20]; KeyStream::keyFromPasswordAndNonce(this->password, nonce, out); m_pConnection->inputKey.init(out + 40, out + 60); m_pConnection->outputKey.init(out, out + 20); std::vector* list = new std::vector(0); for (int i = 0; i < 4; i++) list->push_back(0); list->insert(list->end(), m_pConnection->user.begin(), m_pConnection->user.end()); list->insert(list->end(), nonce.begin(), nonce.end()); m_pConnection->outputKey.encodeMessage(&((*list)[0]), 0, 4, (int)list->size() - 4); return list; } std::vector WALogin::readFeaturesUntilChallengeOrSuccess() { while (ProtocolTreeNode *root = m_pConnection->in->nextTree()) { #ifdef _DEBUG { string tmp = root->toString(); m_pConnection->logData(tmp.c_str()); } #endif if (ProtocolTreeNode::tagEquals(root, "stream:features")) { m_pConnection->supports_receipt_acks = root->getChild("receipt_acks") != NULL; delete root; continue; } if (ProtocolTreeNode::tagEquals(root, "challenge")) { std::vector challengedata(root->data->begin(), root->data->end()); delete root; this->sendResponse(challengedata); m_pConnection->logData("Send response"); std::vector data = this->readSuccess(); m_pConnection->logData("Read success"); return std::vector(data.begin(), data.end()); } if (ProtocolTreeNode::tagEquals(root, "success")) { std::vector ret(root->data->begin(), root->data->end()); this->parseSuccessNode(root); delete root; return ret; } } throw WAException("fell out of loop in readFeaturesAndChallenge", WAException::CORRUPT_STREAM_EX, 0); } void WALogin::parseSuccessNode(ProtocolTreeNode* node) { m_pConnection->out->setSecure(); const string &expiration = node->getAttributeValue("expiration"); if (!expiration.empty()) { this->expire_date = atol(expiration.c_str()); if (this->expire_date == 0) throw WAException("invalid expire date: " + expiration); } const string &kind = node->getAttributeValue("kind"); if (kind == "paid") this->account_kind = 1; else if (kind == "free") this->account_kind = 0; else this->account_kind = -1; } std::vector WALogin::readSuccess() { ProtocolTreeNode *node = m_pConnection->in->nextTree(); if (ProtocolTreeNode::tagEquals(node, "failure")) { delete node; throw WAException("Login failure", WAException::LOGIN_FAILURE_EX, WAException::LOGIN_FAILURE_EX_TYPE_PASSWORD); } ProtocolTreeNode::require(node, "success"); this->parseSuccessNode(node); const string &status = node->getAttributeValue("status"); if (status == "expired") { delete node; throw WAException("Account expired on" + std::string(ctime(&this->expire_date)), WAException::LOGIN_FAILURE_EX, WAException::LOGIN_FAILURE_EX_TYPE_EXPIRED, this->expire_date); } if (status == "active") { if (node->getAttributeValue("expiration").empty()) { delete node; throw WAException("active account with no expiration"); } } else this->account_kind = -1; std::vector data = *node->data; delete node; return data; } WALogin::~WALogin() {}