diff options
| -rw-r--r-- | protocols/WhatsApp/src/WASocketConnection.cpp | 49 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WASocketConnection.h | 7 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp | 289 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h | 1 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp | 111 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h | 7 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp | 263 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/WAConnection.h | 3 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp | 180 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/WALogin.h | 11 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp | 37 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/constants.h | 4 | ||||
| -rw-r--r-- | protocols/WhatsApp/src/version.h | 4 | 
13 files changed, 382 insertions, 584 deletions
diff --git a/protocols/WhatsApp/src/WASocketConnection.cpp b/protocols/WhatsApp/src/WASocketConnection.cpp index b5d1b0235c..41d0b78663 100644 --- a/protocols/WhatsApp/src/WASocketConnection.cpp +++ b/protocols/WhatsApp/src/WASocketConnection.cpp @@ -101,36 +101,38 @@ void WASocketConnection::write(const std::vector<unsigned char>& bytes, int leng  unsigned char WASocketConnection::read()
  {
 -	char c;
 -
  	SetLastError(0);
 -	int result;
 -	//do {
 -	result = Netlib_Recv(this->hConn, &c, 1, 0 /*MSG_NOHTTPGATEWAYWRAP | MSG_NODUMP*/);
 -	//} while  (WSAGetLastError() == EINTR);
 -	if (result <= 0) {
 +
 +	char c;
 +	int result = Netlib_Recv(this->hConn, &c, 1, 0);
 +	if (result <= 0)
  		throw WAException(getLastErrorMsg(), WAException::SOCKET_EX, WAException::SOCKET_EX_RECV);
 -	}
 +
  	return c;
  }
 +int WASocketConnection::read(unsigned char *buf, int length)
 +{
 +	int result = Netlib_Recv(this->hConn, (char*)buf, length, 0);
 +	if (result <= 0)
 +		throw WAException(getLastErrorMsg(), WAException::SOCKET_EX, WAException::SOCKET_EX_RECV);
 +
 +	return result;
 +}
 +
  int WASocketConnection::read(std::vector<unsigned char>& b, int off, int length)
  {
 -	if (off < 0 || length < 0) {
 +	if (off < 0 || length < 0)
  		throw new WAException("Out of bounds", WAException::SOCKET_EX, WAException::SOCKET_EX_RECV);
 -	}
 -	char* buffer = new char[length];
 -	int result = Netlib_Recv(this->hConn, buffer, length, MSG_NOHTTPGATEWAYWRAP | MSG_NODUMP);
 -	if (result <= 0) {
 +	char* buffer = (char*)_alloca(length);
 +	int result = Netlib_Recv(this->hConn, buffer, length, MSG_NOHTTPGATEWAYWRAP | MSG_NODUMP);
 +	if (result <= 0)
  		throw WAException(getLastErrorMsg(), WAException::SOCKET_EX, WAException::SOCKET_EX_RECV);
 -	}
  	for (int i = 0; i < result; i++)
  		b[off + i] = buffer[i];
 -	delete[] buffer;
 -
  	return result;
  }
 @@ -139,6 +141,21 @@ void WASocketConnection::forceShutdown()  	Netlib_Shutdown(this->hConn);
  }
 +void WASocketConnection::dump(const void *pData, int length)
 +{
 +	BYTE *pBuf = (BYTE*)pData;
 +	while (length > 0) {
 +		int portion = (length < 16) ? length : 16;
 +
 +		char str[100];
 +		for (int i = 0; i < portion; i++)
 +			sprintf(str + i * 3, "%02X ", *pBuf++);
 +		Netlib_Logf(WASocketConnection::hNetlibUser, "DATA: %s", str);
 +
 +		length -= portion;
 +	}
 +}
 +
  WASocketConnection::~WASocketConnection()
  {
  	this->forceShutdown();
 diff --git a/protocols/WhatsApp/src/WASocketConnection.h b/protocols/WhatsApp/src/WASocketConnection.h index 48c64f2a1a..c585e98b3d 100644 --- a/protocols/WhatsApp/src/WASocketConnection.h +++ b/protocols/WhatsApp/src/WASocketConnection.h @@ -22,17 +22,20 @@ private:  public:
  	WASocketConnection(const std::string& dir, int port) throw (WAException);
 +	virtual ~WASocketConnection();
 +
  	void write(int i);
  	unsigned char read();
 +	int read(std::vector<unsigned char>& b, int off, int length);
 +	int read(unsigned char*, int length);
  	void flush();
  	void write(const std::vector<unsigned char>& b, int length);
  	void write(const std::vector<unsigned char>& bytes, int offset, int length);
 -	int read(std::vector<unsigned char>& b, int off, int length);
  	void makeNonBlock();
  	int waitForRead();
  	void forceShutdown();
 +	void dump(const void *buf, int length);
 -	virtual ~WASocketConnection();
  	static void initNetwork(HANDLE hNetlibUser) throw (WAException);
  	static void quitNetwork();
  };
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp index 388bf10e4a..573afb4680 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp @@ -11,7 +11,32 @@  #include "ProtocolTreeNode.h"
  #include "utilities.h"
 -BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* connection, const char** dictionary, const int dictionarysize) {
 +static const char *secondary_dict[] = { +	"mpeg4", "wmv", "audio/3gpp", "audio/aac", "audio/amr", "audio/mp4", "audio/mpeg", "audio/ogg", "audio/qcelp", "audio/wav", +	"audio/webm", "audio/x-caf", "audio/x-ms-wma", "image/gif", "image/jpeg", "image/png", "video/3gpp", "video/avi", "video/mp4", +	"video/mpeg", "video/quicktime", "video/x-flv", "video/x-ms-asf", "302", "400", "401", "402", "403", "404", "405", "406", "407", +	"409", "410", "500", "501", "503", "504", "abitrate", "acodec", "app_uptime", "asampfmt", "asampfreq", "audio", "clear", "conflict", +	"conn_no_nna", "cost", "currency", "duration", "extend", "file", "fps", "g_notify", "g_sound", "gcm", "gone", "google_play", "hash", +	"height", "invalid", "jid-malformed", "latitude", "lc", "lg", "live", "location", "log", "longitude", "max_groups", "max_participants", +	"max_subject", "mimetype", "mode", "napi_version", "normalize", "orighash", "origin", "passive", "password", "played", +	"policy-violation", "pop_mean_time", "pop_plus_minus", "price", "pricing", "redeem", "Replaced by new connection", "resume", +	"signature", "size", "sound", "source", "system-shutdown", "username", "vbitrate", "vcard", "vcodec", "video", "width", +	"xml-not-well-formed", "checkmarks", "image_max_edge", "image_max_kbytes", "image_quality", "ka", "ka_grow", "ka_shrink", "newmedia", +	"library", "caption", "forward", "c0", "c1", "c2", "c3", "clock_skew", "cts", "k0", "k1", "login_rtt", "m_id", "nna_msg_rtt", +	"nna_no_off_count", "nna_offline_ratio", "nna_push_rtt", "no_nna_con_count", "off_msg_rtt", "on_msg_rtt", "stat_name", "sts", +	"suspect_conn", "lists", "self", "qr", "web", "w:b", "recipient", "w:stats", "forbidden", "aurora.m4r", "bamboo.m4r", "chord.m4r", +	"circles.m4r", "complete.m4r", "hello.m4r", "input.m4r", "keys.m4r", "note.m4r", "popcorn.m4r", "pulse.m4r", "synth.m4r", "filehash", +	"max_list_recipients", "en-AU", "en-GB", "es-MX", "pt-PT", "zh-Hans", "zh-Hant", "relayelection", "relaylatency", "interruption", +	"Apex.m4r", "Beacon.m4r", "Bulletin.m4r", "By The Seaside.m4r", "Chimes.m4r", "Circuit.m4r", "Constellation.m4r", "Cosmic.m4r", +	"Crystals.m4r", "Hillside.m4r", "Illuminate.m4r", "Night Owl.m4r", "Opening.m4r", "Playtime.m4r", "Presto.m4r", "Radar.m4r", +	"Radiate.m4r", "Ripples.m4r", "Sencha.m4r", "Signal.m4r", "Silk.m4r", "Slow Rise.m4r", "Stargaze.m4r", "Summit.m4r", "Twinkle.m4r", +	"Uplift.m4r", "Waves.m4r", "voip", "eligible", "upgrade", "planned", "current", "future", "disable", "expire", "start", "stop", +	"accuracy", "speed", "bearing", "recording", "encrypt", "key", "identity", "w:gp2", "admin", "locked", "unlocked", "new", "battery", +	"archive", "adm", "plaintext_size", "compressed_size", "delivered", "msg", "pkmsg", "everyone", "v", "transport", "call-id" +}; +
 +BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* connection, const char** dictionary, const int dictionarysize)
 +{
  	this->conn = conn;
  	this->rawIn = connection;
  	this->tokenMap = dictionary;
 @@ -21,14 +46,16 @@ BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* conn  	this->buf = new std::vector<unsigned char>(BUFFER_SIZE);
  }
 -BinTreeNodeReader::~BinTreeNodeReader() {
 +BinTreeNodeReader::~BinTreeNodeReader()
 +{
  	if (this->buf != NULL)
  		delete this->buf;
  	if (this->in != NULL)
  		delete this->in;
  }
 -ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {
 +ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal()
 +{
  	int b = this->in->read();
  	int size = readListSize(b);
  	b = this->in->read();
 @@ -40,7 +67,7 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {  	if ((size == 0) || (tag == NULL))
  		throw WAException("nextTree sees 0 list or null tag", WAException::CORRUPT_STREAM_EX, -1);
  	int attribCount = (size - 2 + size % 2) / 2;
 -	std::map<string,string>* attribs = readAttributes(attribCount);
 +	std::map<string, string>* attribs = readAttributes(attribCount);
  	if (size % 2 == 1) {
  		ProtocolTreeNode* ret = new ProtocolTreeNode(*tag, attribs);
  		delete tag;
 @@ -59,7 +86,8 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {  		std::string* s = (std::string*) obj->data;
  		data = new std::vector<unsigned char>(s->begin(), s->end());
  		delete s;
 -	} else {
 +	}
 +	else {
  		data = (std::vector<unsigned char>*) obj->data;
  	}
 @@ -69,25 +97,31 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {  	return ret;
  }
 -bool BinTreeNodeReader::isListTag(int b) {
 +bool BinTreeNodeReader::isListTag(int b)
 +{
  	return (b == 248) || (b == 0) || (b == 249);
  }
 -void BinTreeNodeReader::decodeStream(int flags, int offset, int length) {
 +void BinTreeNodeReader::decodeStream(int flags, int offset, int length)
 +{
  	if ((flags & 8) != 0) {
 -		if (length < 4) {
 -			throw WAException("invalid length"  + length, WAException::CORRUPT_STREAM_EX, 0);
 -		}
 -		offset += 4;
 +		if (length < 4)
 +			throw WAException("invalid length" + length, WAException::CORRUPT_STREAM_EX, 0);
 +
  		length -= 4;
 -		this->conn->inputKey->decodeMessage(&(*this->buf)[0], offset - 4, offset, length);
 +
 +		unsigned char *pData = (unsigned char*)&(*this->buf)[0];
 +		this->conn->inputKey->decodeMessage(pData, offset + length, 0, length);
 +		this->rawIn->dump(pData + offset, length);
  	}
 +
  	if (this->in != NULL)
  		delete this->in;
  	this->in = new ByteArrayInputStream(this->buf, offset, length);
  }
 -std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount) {
 +std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount)
 +{
  	std::map<string, string>* attribs = new std::map<string, string>();
  	for (int i = 0; i < attribCount; i++) {
  		std::string* key = readStringAsString();
 @@ -99,91 +133,106 @@ std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount) {  	return attribs;
  }
 -std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList(int token) {
 +std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList(int token)
 +{
  	int size = readListSize(token);
  	std::vector<ProtocolTreeNode*>* list = new std::vector<ProtocolTreeNode*>(size);
 -	for (int i = 0; i < size; i++) {
 +	for (int i = 0; i < size; i++)
  		(*list)[i] = nextTreeInternal();
 -	}
  	return list;
  }
 -int BinTreeNodeReader::readListSize(int token) {
 -	int size;
 -	if (token == 0) {
 -		size = 0;
 +int BinTreeNodeReader::readListSize(int token)
 +{
 +	switch (token) {
 +	case 0:   return 0;
 +	case 248: return readInt8(this->in);
 +	case 249: return readInt16(this->in);
 +	default:
 +		throw new WAException("invalid list size in readListSize: token " + token, WAException::CORRUPT_STREAM_EX, 0);
  	}
 -	else {
 -		size = 0;
 -		if (token == 248) {
 -			size = readInt8(this->in);
 -		}
 -		else
 -		{
 -			size = 0;
 -			if (token == 249)
 -				size = readInt16(this->in);
 -			else
 -				throw new WAException("invalid list size in readListSize: token " + token, WAException::CORRUPT_STREAM_EX, 0);
 -		}
 -	}
 -
 -	return size;
 +	return 0;
  }
 -std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList() {
 +std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList()
 +{
  	return readList(this->in->read());
  }
 -ReadData* BinTreeNodeReader::readString() {
 +ReadData* BinTreeNodeReader::readString()
 +{
  	return readString(this->in->read());
  }
 -ReadData* BinTreeNodeReader::readString(int token) {
 -	if (token == -1) {
 +ReadData* BinTreeNodeReader::readString(int token)
 +{
 +	if (token == -1)
  		throw WAException("-1 token in readString", WAException::CORRUPT_STREAM_EX, -1);
 -	}
 +	int bSize;
  	ReadData* ret = new ReadData();
 -	if ((token > 4) && (token < 245)) {
 +	if (token > 2 && token <= this->tokenmapsize) {
 +		if (token != this->tokenmapsize)
 +			ret->data = new std::string(this->tokenMap[token]);
 +		else {
 +			token = readInt8(this->in);
 +			if (token >= 0 && token < _countof(secondary_dict))
 +				ret->data = new std::string(secondary_dict[token]);
 +			else
 +				throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0);
 +		}
 +
  		ret->type = STRING;
 -		ret->data = new std::string(getToken(token));
  		return ret;
  	}
 -	switch(token) {
 +	switch (token) {
  	case 0:
  		return NULL;
 -	case 252: {
 -		int size8 = readInt8(this->in);
 -		std::vector<unsigned char>* buf8 = new std::vector<unsigned char>(size8);
 -		fillArray(*buf8, size8, this->in);
 -		// std::string* ret = new std::string(buf8->begin(), buf8->end());
 -		// delete buf8;
 -		ret->type = ARRAY;
 -		ret->data = buf8;
 -		return ret;
 -	}
 -	case 253: {
 -		int size24 = readInt24(this->in);
 -		std::vector<unsigned char>* buf24 = new std::vector<unsigned char>(size24);
 -		fillArray(*buf24, size24, this->in);
 -		// std::string* ret = new std::string(buf24->begin(), buf24->end());
 -		// delete buf24;
 -		ret->type = ARRAY;
 -		ret->data = buf24;
 +	case 252:
 +		bSize = readInt8(this->in);
 +		{
 +			std::vector<unsigned char>* buf8 = new std::vector<unsigned char>(bSize);
 +			fillArray(*buf8, bSize, this->in);
 +			ret->type = ARRAY;
 +			ret->data = buf8;
 +		}
  		return ret;
 -	}
 -	case 254: {
 -		token = (unsigned char) this->in->read();
 -		ret->type = STRING;
 -		ret->data = new std::string(getToken(245 + token));
 +
 +	case 253:
 +		bSize = readInt24(this->in);
 +		{
 +			std::vector<unsigned char>* buf24 = new std::vector<unsigned char>(bSize);
 +			fillArray(*buf24, bSize, this->in);
 +			ret->type = ARRAY;
 +			ret->data = buf24;
 +		}
  		return ret;
 -	}
 -	case 250: {
 +
 +	case 255: +		bSize = readInt8(this->in); +		{ +			int size = bSize & 0x7f; +			int numnibbles = size * 2 - ((bSize & 0x80) ? 1 : 0); + +			std::vector<unsigned char> tmp(size);
 +			fillArray(tmp, size, this->in);
 +			std::string s; +			for (int i = 0; i < numnibbles; i++) { +				char c = (tmp[i / 2] >> (4 - ((i & 1) << 2))) & 0xF; +				if (c < 10) s += (c + '0'); +				else s += (c - 10 + '-'); +			} + +			ret->type = STRING;
 +			ret->data = new std::string(s);
 +		} +		return ret; +
 +	case 250:
  		std::string* user = readStringAsString();
  		std::string* server = readStringAsString();
  		if ((user != NULL) && (server != NULL)) {
 @@ -201,14 +250,13 @@ ReadData* BinTreeNodeReader::readString(int token) {  		}
  		throw WAException("readString couldn't reconstruct jid", WAException::CORRUPT_STREAM_EX, -1);
  	}
 -	}
 -	throw WAException("readString couldn't match token" + (int) token, WAException::CORRUPT_STREAM_EX, -1);
 +	throw WAException("readString couldn't match token" + (int)token, WAException::CORRUPT_STREAM_EX, -1);
  }
 -std::string* BinTreeNodeReader::objectAsString(ReadData* o) {
 -	if (o->type == STRING) {
 +std::string* BinTreeNodeReader::objectAsString(ReadData* o)
 +{
 +	if (o->type == STRING)
  		return (std::string*) o->data;
 -	}
  	if (o->type == ARRAY) {
  		std::vector<unsigned char>* v = (std::vector<unsigned char>*) o->data;
 @@ -220,61 +268,44 @@ std::string* BinTreeNodeReader::objectAsString(ReadData* o) {  	return NULL;
  }
 -std::string* BinTreeNodeReader::readStringAsString() {
 +std::string* BinTreeNodeReader::readStringAsString()
 +{
  	ReadData* o = this->readString();
  	std::string* ret = this->objectAsString(o);
  	delete o;
  	return ret;
  }
 -std::string* BinTreeNodeReader::readStringAsString(int token) {
 +std::string* BinTreeNodeReader::readStringAsString(int token)
 +{
  	ReadData* o = this->readString(token);
  	std::string* ret = this->objectAsString(o);
  	delete o;
  	return ret;
  }
 -
 -void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ByteArrayInputStream* in) {
 +void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ByteArrayInputStream* in)
 +{
  	int count = 0;
 -	while (count < len) {
 +	while (count < len)
  		count += in->read(buff, count, len - count);
 -	}
  }
 -void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ISocketConnection* in) {
 +void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ISocketConnection* in)
 +{
  	int count = 0;
 -	while (count < len) {
 +	while (count < len)
  		count += in->read(buff, count, len - count);
 -	}
  }
 +void BinTreeNodeReader::getTopLevelStream()
 +{
 +	int stanzaSize = readInt24(this->rawIn);
 +	int flags = (stanzaSize >> 20);
 +	stanzaSize &= 0x0FFFFF;	
 -std::string BinTreeNodeReader::getToken(int token) {
 -	std::string ret;
 -
 -	if ((token >= 0) && (token < this->tokenmapsize))
 -		ret = std::string(this->tokenMap[token]);
 -	if (ret.empty()) {
 -		throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0);
 -	}
 -	return ret;
 -}
 -
 -
 -void BinTreeNodeReader::getTopLevelStream() {
 -	int stanzaSize;
 -	int flags;
 -	int byte = readInt8(this->rawIn);
 -	flags = byte >> 4;
 -	int size0 = byte & 15;
 -	int size1 = readInt8(this->rawIn);
 -	int size2 = readInt8(this->rawIn);
 -
 -	stanzaSize = (size0 << 16) + (size1 << 8) + size2;
 -
 -	if (this->buf->size() < (size_t) stanzaSize) {
 -		int newsize = max((int) (this->buf->size() * 3 / 2), stanzaSize);
 +	if (this->buf->size() < (size_t)stanzaSize) {
 +		int newsize = max((int)(this->buf->size() * 3 / 2), stanzaSize);
  		delete this->buf;
  		this->buf = new std::vector<unsigned char>(newsize);
  	}
 @@ -283,18 +314,21 @@ void BinTreeNodeReader::getTopLevelStream() {  	this->decodeStream(flags, 0, stanzaSize);
  }
 -int BinTreeNodeReader::readInt8(ByteArrayInputStream* in) {
 +int BinTreeNodeReader::readInt8(ByteArrayInputStream* in)
 +{
  	return in->read();
  }
 -int BinTreeNodeReader::readInt16(ByteArrayInputStream* in) {
 +int BinTreeNodeReader::readInt16(ByteArrayInputStream* in)
 +{
  	int intTop = in->read();
  	int intBot = in->read();
  	int value = (intTop << 8) + intBot;
  	return value;
  }
 -int BinTreeNodeReader::readInt24(ByteArrayInputStream* in) {
 +int BinTreeNodeReader::readInt24(ByteArrayInputStream* in)
 +{
  	int int1 = in->read();
  	int int2 = in->read();
  	int int3 = in->read();
 @@ -303,12 +337,14 @@ int BinTreeNodeReader::readInt24(ByteArrayInputStream* in) {  	return value;
  }
 -ProtocolTreeNode* BinTreeNodeReader::nextTree() {
 +ProtocolTreeNode* BinTreeNodeReader::nextTree()
 +{
  	this->getTopLevelStream();
  	return nextTreeInternal();
  }
 -void BinTreeNodeReader::streamStart() {
 +void BinTreeNodeReader::streamStart()
 +{
  	this->getTopLevelStream();
  	int tag = this->in->read();
 @@ -319,26 +355,25 @@ void BinTreeNodeReader::streamStart() {  	}
  	int attribCount = (size - 2 + size % 2) / 2;
 -	std::map<string,string>* attributes = readAttributes(attribCount);
 +	std::map<string, string>* attributes = readAttributes(attribCount);
  	delete attributes;
  }
 -int BinTreeNodeReader::readInt8(ISocketConnection* in) {
 +int BinTreeNodeReader::readInt8(ISocketConnection* in)
 +{
  	return in->read();
  }
 -int BinTreeNodeReader::readInt16(ISocketConnection* in) {
 -	int intTop = in->read();
 -	int intBot = in->read();
 -	int value = (intTop << 8) + intBot;
 -	return value;
 +int BinTreeNodeReader::readInt16(ISocketConnection* in)
 +{
 +	unsigned char data[2];
 +	in->read(data, 2);
 +	return (int(data[0]) << 8) + int(data[1]);
  }
 -int BinTreeNodeReader::readInt24(ISocketConnection* in) {
 -	int int1 = in->read();
 -	int int2 = in->read();
 -	int int3 = in->read();
 -	int value = (int1 << 16) + (int2 << 8) + int3;
 -
 -	return value;
 +int BinTreeNodeReader::readInt24(ISocketConnection* in)
 +{
 +	unsigned char data[3];
 +	in->read(data, 3);
 +	return (int(data[0]) << 16) + (int(data[1]) << 8) + int(data[2]);
  }
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h index 61b70b218b..4288c671f3 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h @@ -54,7 +54,6 @@ private:  	std::string* objectAsString(ReadData* o);
  	std::string* readStringAsString();
  	std::string* readStringAsString(int token);
 -	std::string getToken(int token);
  	void getTopLevelStream();
  	static int readInt8(ByteArrayInputStream* in);
  	static int readInt8(ISocketConnection* in);
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp index 6936de9a8b..b79bdcfd09 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp @@ -10,8 +10,9 @@  #include "utilities.h"
  BinTreeNodeWriter::BinTreeNodeWriter(WAConnection* conn, ISocketConnection* connection,
 -		const char** dictionary, const int dictionarysize, IMutex* mutex) {
 -   this->mutex = mutex;
 +	const char** dictionary, const int dictionarysize, IMutex* mutex)
 +{
 +	this->mutex = mutex;
  	this->conn = conn;
  	this->out = new ByteArrayOutputStream(2048);
  	this->realOut = connection;
 @@ -37,22 +38,19 @@ void BinTreeNodeWriter::processBuffer()  {
  	bool flag = this->conn->outputKey != NULL;
  	unsigned int num = 0u;
 -	if (flag)
 -	{
 +	if (flag) {
  		long num2 = (long)this->out->getLength() + 4L;
  		this->out->setLength(num2);
  		this->out->setPosition(num2);
  		num |= 1u;
  	}
  	long num3 = (long)this->out->getLength() - 3L - (long) this->dataBegin;
 -	if (num3 >= 1048576L)
 -	{
 +	if (num3 >= 1048576L) {
  		throw WAException("Buffer too large: " + num3, WAException::CORRUPT_STREAM_EX, 0);
  	}
  	std::vector<unsigned char>* buffer = this->out->getBuffer();
 -	if (flag)
 -	{
 +	if (flag) {
  		int num4 = (int)num3 - 4;
  		this->conn->outputKey->encodeMessage(buffer->data(), this->dataBegin + 3 + num4, this->dataBegin + 3, num4);
  	}
 @@ -61,15 +59,16 @@ void BinTreeNodeWriter::processBuffer()  	(*buffer)[this->dataBegin + 2] = (unsigned char)(num3 & 255L);
  }
 -void BinTreeNodeWriter::streamStart(std::string domain, std::string resource) {
 +void BinTreeNodeWriter::streamStart(std::string domain, std::string resource)
 +{
  	this->mutex->lock();
  	try {
  		this->out->setPosition(0);
  		this->out->setLength(0);
 -		this->out->write(87);
 -		this->out->write(65);
 +		this->out->write('W');
 +		this->out->write('A');
  		this->out->write(1);
 -		this->out->write(2);
 +		this->out->write(5);
  		std::map<string, string> attributes;
  		attributes["to"] = domain;
 @@ -80,44 +79,53 @@ void BinTreeNodeWriter::streamStart(std::string domain, std::string resource) {  		this->writeAttributes(&attributes);
  		this->processBuffer();
  		this->flushBuffer(true, 0);
 -	} catch (exception& ex) {
 +	}
 +	catch (exception& ex) {
  		this->mutex->unlock();
  		throw ex;
  	}
  	this->mutex->unlock();
  }
 -void BinTreeNodeWriter::writeListStart(int i) {
 +void BinTreeNodeWriter::writeListStart(int i)
 +{
  	if (i == 0) {
  		this->out->write(0);
 -	} else if (i < 256) {
 +	}
 +	else if (i < 256) {
  		this->out->write(248);
  		writeInt8(i);
 -	} else {
 +	}
 +	else {
  		this->out->write(249);
  		writeInt16(i);
  	}
  }
 -void BinTreeNodeWriter::writeInt8(int v) {
 +void BinTreeNodeWriter::writeInt8(int v)
 +{
  	this->out->write(v & 0xFF);
  }
 -void BinTreeNodeWriter::writeInt16(int v, ISocketConnection* o) {
 +void BinTreeNodeWriter::writeInt16(int v, ISocketConnection* o)
 +{
  	o->write((v & 0xFF00) >> 8);
  	o->write((v & 0xFF) >> 0);
  }
 -void BinTreeNodeWriter::writeInt16(int v) {
 +void BinTreeNodeWriter::writeInt16(int v)
 +{
  	writeInt16(v, this->out);
  }
 -void BinTreeNodeWriter::writeInt16(int v, ByteArrayOutputStream* o) {
 +void BinTreeNodeWriter::writeInt16(int v, ByteArrayOutputStream* o)
 +{
  	o->write((v & 0xFF00) >> 8);
  	o->write((v & 0xFF) >> 0);
  }
 -void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes) {
 +void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes)
 +{
  	if (attributes != NULL) {
  		std::map<string, string>::iterator ii;
  		for (ii = attributes->begin(); ii != attributes->end(); ii++) {
 @@ -127,14 +135,15 @@ void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes) {  	}
  }
 -void BinTreeNodeWriter::writeString(const std::string& tag) {
 +void BinTreeNodeWriter::writeString(const std::string& tag)
 +{
  	std::map<string, int>::iterator it = this->tokenMap.find(tag);
  	if (it != this->tokenMap.end())
  		writeToken(it->second);
  	else {
  		size_t atIndex = tag.find('@');
  		if (atIndex == 0 || atIndex == string::npos)
 -			writeBytes((unsigned char*) tag.data(), (int)tag.length());
 +			writeBytes((unsigned char*)tag.data(), (int)tag.length());
  		else {
  			std::string server = tag.substr(atIndex + 1);
  			std::string user = tag.substr(0, atIndex);
 @@ -143,18 +152,21 @@ void BinTreeNodeWriter::writeString(const std::string& tag) {  	}
  }
 -void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server) {
 +void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server)
 +{
  	this->out->write(250);
  	if (user != NULL && !user->empty()) {
  		writeString(*user);
 -	} else {
 +	}
 +	else {
  		writeToken(0);
  	}
  	writeString(server);
  }
 -void BinTreeNodeWriter::writeToken(int intValue) {
 +void BinTreeNodeWriter::writeToken(int intValue)
 +{
  	if (intValue < 245)
  		this->out->write(intValue);
  	else if (intValue <= 500) {
 @@ -163,32 +175,36 @@ void BinTreeNodeWriter::writeToken(int intValue) {  	}
  }
 -void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length) {
 +void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length)
 +{
  	if (length >= 256) {
  		this->out->write(253);
  		writeInt24(length);
 -	} else {
 +	}
 +	else {
  		this->out->write(252);
  		writeInt8(length);
  	}
  	this->out->write(bytes, length);
  }
 -void BinTreeNodeWriter::writeInt24(int v) {
 +void BinTreeNodeWriter::writeInt24(int v)
 +{
  	this->out->write((v & 0xFF0000) >> 16);
  	this->out->write((v & 0xFF00) >> 8);
  	this->out->write(v & 0xFF);
  }
 -void BinTreeNodeWriter::writeInternal(ProtocolTreeNode* node) {
 +void BinTreeNodeWriter::writeInternal(ProtocolTreeNode* node)
 +{
  	writeListStart(
 -			1 + (node->attributes == NULL ? 0 : (int)node->attributes->size() * 2)
 -			+ (node->children == NULL ? 0 : 1)
 -			+ (node->data == NULL ? 0 : 1));
 +		1 + (node->attributes == NULL ? 0 : (int)node->attributes->size() * 2)
 +		+ (node->children == NULL ? 0 : 1)
 +		+ (node->data == NULL ? 0 : 1));
  	writeString(node->tag);
  	writeAttributes(node->attributes);
  	if (node->data != NULL) {
 -		writeBytes((unsigned char*) node->data->data(), (int)node->data->size());
 +		writeBytes((unsigned char*)node->data->data(), (int)node->data->size());
  	}
  	if (node->children != NULL && !node->children->empty()) {
  		writeListStart((int)node->children->size());
 @@ -203,10 +219,12 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork)  	this->flushBuffer(flushNetwork, this->dataBegin);
  }
 -void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {
 +void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset)
 +{
  	try {
  		this->processBuffer();
 -	} catch (WAException& ex) {
 +	}
 +	catch (WAException& ex) {
  		this->out->setPosition(0);
  		this->out->setLength(0);
  		throw ex;
 @@ -216,8 +234,7 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {  	std::vector<unsigned char> buffer(this->out->getBuffer()->begin(), this->out->getBuffer()->end());
  	int num = (int)(this->out->getLength() - (long)startingOffset);
 -	if (flushNetwork && ((long)this->out->getCapacity() - this->out->getLength() < 3L || this->out->getLength() > 4096L))
 -	{
 +	if (flushNetwork && ((long)this->out->getCapacity() - this->out->getLength() < 3L || this->out->getLength() > 4096L)) {
  		delete this->out;
  		this->out = new ByteArrayOutputStream(4096);
  	}
 @@ -226,24 +243,28 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {  		this->realOut->write(buffer, startingOffset, num);
  }
 -void BinTreeNodeWriter::streamEnd() {
 +void BinTreeNodeWriter::streamEnd()
 +{
  	this->mutex->lock();
  	try {
  		writeListStart(1);
  		this->out->write(2);
  		flushBuffer(true);
 -	} catch (exception& ex) {
 +	}
 +	catch (exception& ex) {
  		this->mutex->unlock();
  		throw ex;
  	}
  	this->mutex->unlock();
  }
 -void BinTreeNodeWriter::write(ProtocolTreeNode* node) {
 +void BinTreeNodeWriter::write(ProtocolTreeNode* node)
 +{
  	write(node, true);
  }
 -void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush) {
 +void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush)
 +{
  	this->mutex->lock();
  	try {
  		this->writeDummyHeader();
 @@ -253,14 +274,16 @@ void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush) {  			writeInternal(node);
  		}
  		flushBuffer(needsFlush);
 -	} catch (exception& ex) {
 +	}
 +	catch (exception& ex) {
  		this->mutex->unlock();
  		throw WAException(ex.what());
  	}
  	this->mutex->unlock();
  }
 -BinTreeNodeWriter::~BinTreeNodeWriter() {
 +BinTreeNodeWriter::~BinTreeNodeWriter()
 +{
  	if (this->out != NULL)
  		delete this->out;
  }
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h b/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h index a2d82efc64..b9fa3d5faa 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h +++ b/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h @@ -7,19 +7,20 @@ class ISocketConnection {  public:
     ISocketConnection() {}
 +	virtual ~ISocketConnection() {}
 +
  	virtual void write(int i) = 0;
  	virtual unsigned char read() = 0;
  	virtual void flush() = 0;
  	virtual void write(const std::vector<unsigned char>& b, int length) = 0;
  	virtual void write(const std::vector<unsigned char>& bytes, int offset, int length) = 0;
 +	virtual int read(unsigned char*, int length) = 0;
  	virtual int read(std::vector<unsigned char>& b, int off, int length) = 0;
  	virtual void makeNonBlock() = 0;
  	virtual int waitForRead() = 0;
  	virtual void forceShutdown() = 0;
 -   virtual ~ISocketConnection() {}
 -	//static void initNetwork();
 -	//static void quitNetwork();
 +	virtual void dump(const void *buf, int length) = 0;
  };
  #endif /* ISOCKETCONNECTION_H_ */
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp index 8fb24b443b..352d49b07d 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp @@ -12,245 +12,31 @@  #include "utilities.h"
  const char* WAConnection::dictionary[] = {
 -		"",
 -		"",
 -		"",
 -		"",
 -		"",
 -		"account",
 -		"ack",
 -		"action",
 -		"active",
 -		"add",
 -		"after",
 -		"ib",
 -		"all",
 -		"allow",
 -		"apple",
 -		"audio",
 -		"auth",
 -		"author",
 -		"available",
 -		"bad-protocol",
 -		"bad-request",
 -		"before",
 -		"Bell.caf",
 -		"body",
 -		"Boing.caf",
 -		"cancel",
 -		"category",
 -		"challenge",
 -		"chat",
 -		"clean",
 -		"code",
 -		"composing",
 -		"config",
 -		"conflict",
 -		"contacts",
 -		"count",
 -		"create",
 -		"creation",
 -		"default",
 -		"delay",
 -		"delete",
 -		"delivered",
 -		"deny",
 -		"digest",
 -		"DIGEST-MD5-1",
 -		"DIGEST-MD5-2",
 -		"dirty",
 -		"elapsed",
 -		"broadcast",
 -		"enable",
 -		"encoding",
 -		"duplicate",
 -		"error",
 -		"event",
 -		"expiration",
 -		"expired",
 -		"fail",
 -		"failure",
 -		"false",
 -		"favorites",
 -		"feature",
 -		"features",
 -		"field",
 -		"first",
 -		"free",
 -		"from",
 -		"g.us",
 -		"get",
 -		"Glass.caf",
 -		"google",
 -		"group",
 -		"groups",
 -		"g_notify",
 -		"g_sound",
 -		"Harp.caf",
 -		"http://etherx.jabber.org/streams",
 -		"http://jabber.org/protocol/chatstates",
 -		"id",
 -		"image",
 -		"img",
 -		"inactive",
 -		"index",
 -		"internal-server-error",
 -		"invalid-mechanism",
 -		"ip",
 -		"iq",
 -		"item",
 -		"item-not-found",
 -		"user-not-found",
 -		"jabber:iq:last",
 -		"jabber:iq:privacy",
 -		"jabber:x:delay",
 -		"jabber:x:event",
 -		"jid",
 -		"jid-malformed",
 -		"kind",
 -		"last",
 -		"latitude",
 -		"lc",
 -		"leave",
 -		"leave-all",
 -		"lg",
 -		"list",
 -		"location",
 -		"longitude",
 -		"max",
 -		"max_groups",
 -		"max_participants",
 -		"max_subject",
 -		"mechanism",
 -		"media",
 -		"message",
 -		"message_acks",
 -		"method",
 -		"microsoft",
 -		"missing",
 -		"modify",
 -		"mute",
 -		"name",
 -		"nokia",
 -		"none",
 -		"not-acceptable",
 -		"not-allowed",
 -		"not-authorized",
 -		"notification",
 -		"notify",
 -		"off",
 -		"offline",
 -		"order",
 -		"owner",
 -		"owning",
 -		"paid",
 -		"participant",
 -		"participants",
 -		"participating",
 -		"password",
 -		"paused",
 -		"picture",
 -		"pin",
 -		"ping",
 -		"platform",
 -		"pop_mean_time",
 -		"pop_plus_minus",
 -		"port",
 -		"presence",
 -		"preview",
 -		"probe",
 -		"proceed",
 -		"prop",
 -		"props",
 -		"p_o",
 -		"p_t",
 -		"query",
 -		"raw",
 -		"reason",
 -		"receipt",
 -		"receipt_acks",
 -		"received",
 -		"registration",
 -		"relay",
 -		"remote-server-timeout",
 -		"remove",
 -		"Replaced by new connection",
 -		"request",
 -		"required",
 -		"resource",
 -		"resource-constraint",
 -		"response",
 -		"result",
 -		"retry",
 -		"rim",
 -		"s.whatsapp.net",
 -		"s.us",
 -		"seconds",
 -		"server",
 -		"server-error",
 -		"service-unavailable",
 -		"set",
 -		"show",
 -		"sid",
 -		"silent",
 -		"sound",
 -		"stamp",
 -		"unsubscribe",
 -		"stat",
 -		"status",
 -		"stream:error",
 -		"stream:features",
 -		"subject",
 -		"subscribe",
 -		"success",
 -		"sync",
 -		"system-shutdown",
 -		"s_o",
 -		"s_t",
 -		"t",
 -		"text",
 -		"timeout",
 -		"TimePassing.caf",
 -		"timestamp",
 -		"to",
 -		"Tri-tone.caf",
 -		"true",
 -		"type",
 -		"unavailable",
 -		"uri",
 -		"url",
 -		"urn:ietf:params:xml:ns:xmpp-sasl",
 -		"urn:ietf:params:xml:ns:xmpp-stanzas",
 -		"urn:ietf:params:xml:ns:xmpp-streams",
 -		"urn:xmpp:delay",
 -		"urn:xmpp:ping",
 -		"urn:xmpp:receipts",
 -		"urn:xmpp:whatsapp",
 -		"urn:xmpp:whatsapp:account",
 -		"urn:xmpp:whatsapp:dirty",
 -		"urn:xmpp:whatsapp:mms",
 -		"urn:xmpp:whatsapp:push",
 -		"user",
 -		"username",
 -		"value",
 -		"vcard",
 -		"version",
 -		"video",
 -		"w",
 -		"w:g",
 -		"w:p",
 -		"w:p:r",
 -		"w:profile:picture",
 -		"wait",
 -		"x",
 -		"xml-not-well-formed",
 -		"xmlns",
 -		"xmlns:stream",
 -		"Xylophone.caf",
 -		"1",
 -		"WAUTH-1"
 +	"", "", "", "account", "ack", "action", "active", "add", "after", "all", "allow", "apple", "auth", "author", "available", +	"bad-protocol", "bad-request", "before", "body", "broadcast", "cancel", "category", "challenge", "chat", "clean", "code", +	"composing", "config", "contacts", "count", "create", "creation", "debug", "default", "delete", "delivery", "delta", "deny", +	"digest", "dirty", "duplicate", "elapsed", "enable", "encoding", "error", "event", "expiration", "expired", "fail", "failure", +	"false", "favorites", "feature", "features", "feature-not-implemented", "field", "first", "free", "from", "g.us", "get", "google", +	"group", "groups", "groups_v2", "http://etherx.jabber.org/streams", "http://jabber.org/protocol/chatstates", "ib", "id", "image", +	"img", "index", "internal-server-error", "ip", "iq", "item-not-found", "item", "jabber:iq:last", "jabber:iq:privacy", "jabber:x:event", +	"jid", "kind", "last", "leave", "list", "max", "mechanism", "media", "message_acks", "message", "method", "microsoft", "missing", +	"modify", "mute", "name", "nokia", "none", "not-acceptable", "not-allowed", "not-authorized", "notification", "notify", "off", +	"offline", "order", "owner", "owning", "p_o", "p_t", "paid", "participant", "participants", "participating", "paused", "picture", +	"pin", "ping", "platform", "port", "presence", "preview", "probe", "prop", "props", "query", "raw", "read", "readreceipts", "reason", +	"receipt", "relay", "remote-server-timeout", "remove", "request", "required", "resource-constraint", "resource", "response", "result", +	"retry", "rim", "s_o", "s_t", "s.us", "s.whatsapp.net", "seconds", "server-error", "server", "service-unavailable", "set", "show", "silent", +	"stat", "status", "stream:error", "stream:features", "subject", "subscribe", "success", "sync", "t", "text", "timeout", "timestamp", "to", +	"true", "type", "unavailable", "unsubscribe", "uri", "url", "urn:ietf:params:xml:ns:xmpp-sasl", "urn:ietf:params:xml:ns:xmpp-stanzas", +	"urn:ietf:params:xml:ns:xmpp-streams", "urn:xmpp:ping", "urn:xmpp:whatsapp:account", "urn:xmpp:whatsapp:dirty", "urn:xmpp:whatsapp:mms", +	"urn:xmpp:whatsapp:push", "urn:xmpp:whatsapp", "user", "user-not-found", "value", "version", "w:g", "w:p:r", "w:p", "w:profile:picture", +	"w", "wait", "WAUTH-2", "xmlns:stream", "xmlns", "1", "chatstate", "crypto", "phash", "enc", "class", "off_cnt", "w:g2", "promote", +	"demote", "creator", "Bell.caf", "Boing.caf", "Glass.caf", "Harp.caf", "TimePassing.caf", "Tri-tone.caf", "Xylophone.caf", "background", +	"backoff", "chunked", "context", "full", "in", "interactive", "out", "registration", "sid", "urn:xmpp:whatsapp:sync", "flt", "s16", "u8", +	"adpcm", "amrnb", "amrwb", "mp3", "pcm", "qcelp", "wma", "h263", "h264", "jpeg"  };
 +const int WAConnection::DICTIONARY_LEN = _countof(WAConnection::dictionary);
 +
  WAConnection::WAConnection(IMutex* mutex, WAListener* event_handler, WAGroupListener* group_event_handler)
  {
  	this->init(event_handler, group_event_handler, mutex);
 @@ -263,9 +49,8 @@ WAConnection::~WAConnection()  	delete this->in;
  	delete this->out;
  	std::map<string, IqResultHandler*>::iterator it;
 -	for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++) {
 +	for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++)
  		delete it->second;
 -	}
  }
  void WAConnection::init(WAListener* event_handler, WAGroupListener* group_event_handler, IMutex* mutex)
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h index 9fbfde8484..92a8b82e4c 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h @@ -393,13 +393,12 @@ class WAConnection {  	time_t expire_date;
  	int account_kind;
  	time_t lastTreeRead;
 -	static const int DICTIONARY_LEN = 237;
 +	static const int DICTIONARY_LEN;
  	static const char* dictionary[];
  	static MessageStore* message_store;
  	KeyStream* inputKey;
  	KeyStream* outputKey;
 -
  	static std::string removeResourceFromJid(const std::string& jid);
  	WALogin* getLogin();
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp index 311edc70a5..459cc7efe9 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp @@ -7,7 +7,6 @@  #include "WALogin.h"
  #include "ByteArray.h"
 -//#include "ApplicationData.h"
  #include "ProtocolTreeNode.h"
  #include "WAException.h"
  #include <iostream>
 @@ -56,86 +55,26 @@ std::vector<unsigned char>* WALogin::login(const std::vector<unsigned char>& aut  	return this->readFeaturesUntilChallengeOrSuccess();
  }
 -BinTreeNodeReader* WALogin::getTreeNodeReader() {
 +BinTreeNodeReader* WALogin::getTreeNodeReader()
 +{
  	return this->inn;
  }
 -BinTreeNodeWriter* WALogin::getTreeNodeWriter() {
 +BinTreeNodeWriter* WALogin::getTreeNodeWriter()
 +{
  	return this->out;
  }
 -std::string WALogin::getResponse(const std::string& challenge) {
 -	unsigned char md5_buffer[16];
 -
 -	size_t i = challenge.find(WALogin::NONCE_KEY);
 -	i += WALogin::NONCE_KEY.length();
 -
 -	size_t j = challenge.find('"', i);
 -	std::string nonce = challenge.substr(i,j-i);
 -
 -	std::string cnonce = str(absLong(randLong()), 36);
 -	_LOGDATA("cnonce = %s", cnonce.c_str());
 -	std::string nc = "00000001";
 -	std::string cinfo(this->user + ":" + this->domain + ":" + this->password);
 -
 -	_LOGDATA("cinfo = %s", cinfo.c_str());
 -
 -	ByteArrayOutputStream bos;
 -	bos.write(utils::md5string(cinfo, md5_buffer), SIZEOF(md5_buffer));
 -	bos.write(58);
 -	bos.write(nonce);
 -	bos.write(58);
 -	bos.write(cnonce);
 -	// bos.print();
 -
 -	std::string digest_uri = "xmpp/" + this->domain;
 -	std::vector<unsigned char>* A1 = bos.toByteArray();
 -	std::string A2 = "AUTHENTICATE:" + digest_uri;
 -	std::string KD = bytesToHex(utils::md5string(&A1->front(), (int)A1->size(), md5_buffer), SIZEOF(md5_buffer));
 -	KD += + ":" + nonce + ":" + nc + ":" + cnonce + ":auth:" + bytesToHex(utils::md5string(A2, md5_buffer), SIZEOF(md5_buffer));
 -
 -	_LOGDATA("KD = %s", KD.c_str());
 -
 -	std::string response = bytesToHex(utils::md5string(KD, md5_buffer), SIZEOF(md5_buffer));
 -
 -	_LOGDATA("response = %s", response.c_str());
 -
 -	std::string bigger_response;
 -	bigger_response.append("realm=\"");
 -	bigger_response.append(this->domain);
 -	bigger_response.append("\",response=");
 -	bigger_response.append(response);
 -	bigger_response.append(",nonce=\"");
 -	bigger_response.append(nonce);
 -	bigger_response.append("\",digest-uri=\"");
 -	bigger_response.append(digest_uri);
 -	bigger_response.append("\",cnonce=\"");
 -	bigger_response.append(cnonce);
 -	bigger_response.append("\",qop=auth");
 -	bigger_response.append(",username=\"");
 -	bigger_response.append(this->user);
 -	bigger_response.append("\",nc=");
 -	bigger_response.append(nc);
 -
 -	_LOGDATA("biggerresponse = %s", bigger_response.c_str());
 -
 -	delete A1;
 -
 -	return bigger_response;
 -}
 -
  void WALogin::sendResponse(const std::vector<unsigned char>& challengeData) {
  	std::vector<unsigned char>* authBlob = this->getAuthBlob(challengeData);
 -	// std::string response = this->getResponse(challengeData);
 -	std::map<string, string> *attributes = new std::map<string,string>();
 -	(*attributes)["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
 -	ProtocolTreeNode node("response", attributes, authBlob);
 +	ProtocolTreeNode node("response", NULL, authBlob);
  	this->out->write(&node);
  }
 -void WALogin::sendFeatures() {
 +void WALogin::sendFeatures()
 +{
  	ProtocolTreeNode* child = new ProtocolTreeNode("receipt_acks", NULL);
  	std::vector<ProtocolTreeNode*>* children = new std::vector<ProtocolTreeNode*>();
  	children->push_back(child);
 @@ -151,47 +90,47 @@ void WALogin::sendFeatures() {  	this->out->write(&node, true);
  }
 -void WALogin::sendAuth(const std::vector<unsigned char>& existingChallenge) {
 +void WALogin::sendAuth(const std::vector<unsigned char>& existingChallenge)
 +{
  	std::vector<unsigned char>* data = NULL;
  	if (!existingChallenge.empty()) {
  		data = this->getAuthBlob(existingChallenge);
  	}
  	std::map<string, string>* attributes = new std::map<string, string>();
 -	(*attributes)["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
 -	(*attributes)["mechanism"] = "WAUTH-1";
 +	(*attributes)["mechanism"] = "WAUTH-2";
  	(*attributes)["user"] = this->user;
  	ProtocolTreeNode node("auth", attributes, data, NULL);
  	this->out->write(&node, true);
  }
 -std::vector<unsigned char>* WALogin::getAuthBlob(const std::vector<unsigned char>& nonce) {
 -	unsigned char out[20];
 +std::vector<unsigned char>* WALogin::getAuthBlob(const std::vector<unsigned char>& nonce)
 +{
 +	unsigned char out[4*20];
  	KeyStream::keyFromPasswordAndNonce(this->password, nonce, out);
  	if (this->connection->inputKey != NULL)
  		delete this->connection->inputKey;
 -	this->connection->inputKey = new KeyStream(out, 20);
 +	this->connection->inputKey = new KeyStream(out + 40, out + 60);
  	if (this->outputKey != NULL)
  		delete this->outputKey;
 +	this->outputKey = new KeyStream(out, out + 20);
 -	this->outputKey = new KeyStream(out, 20);
  	std::vector<unsigned char>* list = new std::vector<unsigned char>(0);
  	for (int i = 0; i < 4; i++)
  		list->push_back(0);
  	list->insert(list->end(), this->user.begin(), this->user.end());
  	list->insert(list->end(), nonce.begin(), nonce.end());
 -	std::string strTime = Utilities::intToStr( time(NULL));
 -	list->insert(list->end(), strTime.begin(), strTime.end());
  	this->outputKey->encodeMessage(&((*list)[0]), 0, 4, (int)list->size() - 4);
  	return list;
  }
 -std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess() {
 +std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess()
 +{
  	ProtocolTreeNode* root;
  	while ((root = this->inn->nextTree()) != NULL) {
  		if (ProtocolTreeNode::tagEquals(root, "stream:features")) {
 @@ -221,7 +160,8 @@ std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess() {  	throw WAException("fell out of loop in readFeaturesAndChallenge", WAException::CORRUPT_STREAM_EX, 0);
  }
 -void WALogin::parseSuccessNode(ProtocolTreeNode* node) {
 +void WALogin::parseSuccessNode(ProtocolTreeNode* node)
 +{
  	const string &expiration = node->getAttributeValue("expiration");
  	if (!expiration.empty()) {
  		this->expire_date = atol(expiration.c_str());
 @@ -242,7 +182,8 @@ void WALogin::parseSuccessNode(ProtocolTreeNode* node) {  	this->connection->outputKey = this->outputKey;
  }
 -std::vector<unsigned char> WALogin::readSuccess() {
 +std::vector<unsigned char> WALogin::readSuccess()
 +{
  	ProtocolTreeNode* node = this->inn->nextTree();
  	if (ProtocolTreeNode::tagEquals(node, "failure")) {
 @@ -271,58 +212,79 @@ std::vector<unsigned char> WALogin::readSuccess() {  	return data;
  }
 -WALogin::~WALogin() {
 -}
 +WALogin::~WALogin()
 +{}
 -KeyStream::KeyStream(unsigned char* key, size_t keyLength) {
 -	unsigned char drop[256];
 +KeyStream::KeyStream(unsigned char* _key, unsigned char* _keyMac) :
 +	seq(0)
 +{
 +	memcpy(key, _key, 20);
 +	memcpy(keyMac, _keyMac, 20);
 -	this->key = new unsigned char[keyLength];
 -	memcpy(this->key, key, keyLength);
 -	this->keyLength = (int)keyLength;
 +	RC4_set_key(&this->rc4, 20, this->key);
 -	RC4_set_key(&this->rc4, this->keyLength, this->key);
 -	RC4(&this->rc4, 256, drop, drop);
 -	HMAC_CTX_init(&this->hmac);
 +	unsigned char drop[768];
 +	RC4(&this->rc4, sizeof(drop), drop, drop);
 + +	HMAC_CTX_init(&hmac);  }
 -KeyStream::~KeyStream() {
 -	delete [] this->key;
 -	HMAC_CTX_cleanup(&this->hmac);
 +KeyStream::~KeyStream()
 +{
 +	HMAC_CTX_cleanup(&hmac);  }
 -void KeyStream::keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out) {
 -	PKCS5_PBKDF2_HMAC_SHA1(pass.data(), (int)pass.size(), nonce.data(), (int)nonce.size(), 16, 20, out);
 +void KeyStream::keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out)
 +{
 +	size_t cbSize = nonce.size();
 +
 +	uint8_t *pNonce = (uint8_t*)_alloca(cbSize + 1);
 +	memcpy(pNonce, nonce.data(), cbSize);
 +
 +	for (int i = 0; i < 4; i++) {
 +		pNonce[cbSize] = i + 1;
 +		PKCS5_PBKDF2_HMAC_SHA1(pass.data(), (int)pass.size(), pNonce, (int)cbSize+1, 2, 20, out + i*20);
 +	}
  }
 -void KeyStream::decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length) {
 +void KeyStream::decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length)
 +{
  	unsigned char digest[20];
  	this->hmacsha1(buffer + offset, length, digest);
 -	for (int i = 0; i < 4; i++) {
 -		if (buffer[macOffset + i] != digest[i]) {
 -			throw WAException("invalid MAC", WAException::CORRUPT_STREAM_EX, 0);
 -		}
 -	}
 -	unsigned char* out = new unsigned char[length];
 +	if (memcmp(&buffer[macOffset], digest, 4))
 +		throw WAException("invalid MAC", WAException::CORRUPT_STREAM_EX, 0);
 +
 +	unsigned char* out = (unsigned char*)_alloca(length);
  	RC4(&this->rc4, length, buffer + offset, out);
  	memcpy(buffer + offset, out, length);
 -   delete[] out;
  }
 -void KeyStream::encodeMessage(unsigned char* buffer, int macOffset, int offset, const int length) {
 -	unsigned char* out = new unsigned char[length];
 +void KeyStream::encodeMessage(unsigned char* buffer, int macOffset, int offset, const int length)
 +{
 +	unsigned char* out = (unsigned char*)_alloca(length);
  	RC4(&this->rc4, length, buffer + offset, out);
  	memcpy(buffer + offset, out, length);
 -   delete[] out;
  	unsigned char digest[20];
  	this->hmacsha1(buffer + offset, length, digest);
 -
  	memcpy(buffer + macOffset, digest, 4);
  }
 -void KeyStream::hmacsha1(unsigned char* text, int textLength, unsigned char *out) {
 +void KeyStream::hmacsha1(unsigned char* text, int textLength, unsigned char *out)
 +{
 +	HMAC_Init(&hmac, this->keyMac, 20, EVP_sha1()); +	HMAC_Update(&hmac, text, textLength); + +	unsigned char hmacInt[4]; +	hmacInt[0] = (this->seq >> 24); +	hmacInt[1] = (this->seq >> 16); +	hmacInt[2] = (this->seq >> 8); +	hmacInt[3] = (this->seq); +	HMAC_Update(&hmac, hmacInt, sizeof(hmacInt)); +
  	unsigned int mdLength;
 -	HMAC(EVP_sha1(), this->key, this->keyLength, text, textLength, out, &mdLength);
 +	HMAC_Final(&hmac, out, &mdLength); + +	this->seq++;  }
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h index 868e806880..2949213e53 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h @@ -23,15 +23,15 @@ class BinTreeNodeWriter;  class KeyStream {
  private:
  	RC4_KEY rc4;
 -	HMAC_CTX hmac;
 -	unsigned char* key;
 -	int keyLength;
 +	unsigned char key[20], keyMac[20];
 +	int seq;
 +	HMAC_CTX hmac;  	void hmacsha1(unsigned char* text, int textLength, unsigned char *out);
  public:
 -	KeyStream(unsigned char* key, size_t keyLegnth);
 -	virtual ~KeyStream();
 +	KeyStream(unsigned char* _key, unsigned char* _keyMac);
 +	~KeyStream();
  	static void keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out);
  	void decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length);
 @@ -54,7 +54,6 @@ private:  	std::vector<unsigned char>* readFeaturesUntilChallengeOrSuccess();
  	void parseSuccessNode(ProtocolTreeNode* node);
  	std::vector<unsigned char> readSuccess();
 -	std::string getResponse(const std::string& challenge);
  public:
  	std::string user;
 diff --git a/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp b/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp index a27c3c42eb..d2ff14411a 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp @@ -13,41 +13,16 @@ using namespace Utilities;  /////////////////////////////////////////////////////////////////////////////////////////
  // Token generation
 -static char WaKey[] = "/UIGKU1FVQa+ATM2A0za7G2KI9S/CwPYjgAbc67v7ep42eO/WeTLx1lb1cHwxpsEgF4+PmYpLd2YpGUdX/A2JQitsHzDwgcdBpUf7psX1BU=";
 -static char WaSignature[] = "MIIDMjCCAvCgAwIBAgIETCU2pDALBgcqhkjOOAQDBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMRYwFAYDVQQKEw1XaGF0c0FwcCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEUMBIGA1UEAxMLQnJpYW4gQWN0b24wHhcNMTAwNjI1MjMwNzE2WhcNNDQwMjE1MjMwNzE2WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExFjAUBgNVBAoTDVdoYXRzQXBwIEluYy4xFDASBgNVBAsTC0VuZ2luZWVyaW5nMRQwEgYDVQQDEwtCcmlhbiBBY3RvbjCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDRGYtLgWh7zyRtQainJfCpiaUbzjJuhMgo4fVWZIvXHaSHBU1t5w//S0lDK2hiqkj8KpMWGywVov9eZxZy37V26dEqr/c2m5qZ0E+ynSu7sqUD7kGx/zeIcGT0H+KAVgkGNQCo5Uc0koLRWYHNtYoIvt5R3X6YZylbPftF/8ayWTALBgcqhkjOOAQDBQADLwAwLAIUAKYCp0d6z4QQdyN74JDfQ2WCyi8CFDUM4CaNB+ceVXdKtOrNTQcc0e+t";
 -static char WaClassesMd5[] = "xOyKd7AoN0uoos7Fkeup5w=="; // 2.11.407
 +static char WaToken[] = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1418865329241";
  std::string WAToken::GenerateToken(const string &number)
  {
 -	unsigned int keyLen, dataLen, classesLen;
 -	mir_ptr<BYTE> key((BYTE*)mir_base64_decode(WaKey, &keyLen));
 -	mir_ptr<BYTE> data((BYTE*)mir_base64_decode(WaSignature, &dataLen));
 -	mir_ptr<BYTE> classes((BYTE*)mir_base64_decode(WaClassesMd5, &classesLen));
 -
 -	BYTE opad[64], ipad[64];
 -	memset(opad, 0x5C, sizeof(opad));
 -	memset(ipad, 0x36, sizeof(ipad));
 -	for (int i = 0; i < sizeof(opad); i++) {
 -		opad[i] = (BYTE)(opad[i] ^ key[i]);
 -		ipad[i] = (BYTE)(ipad[i] ^ key[i]);
 -	}
 +	uint8_t digest[16];
 +	md5_string(WaToken + number, digest);
 -	BYTE hash1[MIR_SHA1_HASH_SIZE], hash2[MIR_SHA1_HASH_SIZE];
 -	mir_sha1_ctx ctx;
 -	mir_sha1_init(&ctx);
 -	mir_sha1_append(&ctx, ipad, sizeof(ipad));
 -	mir_sha1_append(&ctx, data, dataLen);
 -	mir_sha1_append(&ctx, classes, classesLen);
 -	mir_sha1_append(&ctx, (PBYTE)number.c_str(), (int)number.size());
 -	mir_sha1_finish(&ctx, hash1);
 -
 -	mir_sha1_init(&ctx);
 -	mir_sha1_append(&ctx, opad, sizeof(opad));
 -	mir_sha1_append(&ctx, hash1, sizeof(hash1));
 -	mir_sha1_finish(&ctx, hash2);
 -
 -	ptrA result(mir_urlEncode(ptrA(mir_base64_encode(hash2, sizeof(hash2)))));
 -	return std::string(result);
 +	char dest[33];
 +	bin2hex(digest, sizeof(digest), dest);
 +	return dest;
  }
  /////////////////////////////////////////////////////////////////////////////////////////
 diff --git a/protocols/WhatsApp/src/constants.h b/protocols/WhatsApp/src/constants.h index 6b292eb218..ccb9c9a332 100644 --- a/protocols/WhatsApp/src/constants.h +++ b/protocols/WhatsApp/src/constants.h @@ -33,7 +33,7 @@  // WhatsApp
  #define WHATSAPP_LOGIN_SERVER "c.whatsapp.net"
 -#define ACCOUNT_USER_AGENT "WhatsApp/2.11.407 Android/4.0.4 Device/GalaxyS3"
 +#define ACCOUNT_USER_AGENT "WhatsApp/2.12.60 S40Version/14.26 Device/Nokia302"
  #define ACCOUNT_URL_CODEREQUEST "https://r.whatsapp.net/v1/code.php"
  #define ACCOUNT_URL_CODEREQUESTV2 "https://v.whatsapp.net/v2/code"
  #define ACCOUNT_URL_REGISTERREQUEST "https://r.whatsapp.net/v1/register.php"
 @@ -42,7 +42,7 @@  #define ACCOUNT_URL_EXISTSV2 "https://v.whatsapp.net/v2/exist"
  // WhatsApp Nokia 302 S40
 -#define ACCOUNT_RESOURCE  "S40-2.12.49"
 +#define ACCOUNT_RESOURCE  "S40-2.12.60"
  #define WHATSAPP_RECV_MESSAGE 1
  #define WHATSAPP_SEND_MESSAGE 2
 diff --git a/protocols/WhatsApp/src/version.h b/protocols/WhatsApp/src/version.h index 684deffc8a..0a73307133 100644 --- a/protocols/WhatsApp/src/version.h +++ b/protocols/WhatsApp/src/version.h @@ -1,7 +1,7 @@  #define __MAJOR_VERSION          0
  #define __MINOR_VERSION          1
 -#define __RELEASE_NUM            0
 -#define __BUILD_NUM              5
 +#define __RELEASE_NUM            1
 +#define __BUILD_NUM              0
  #include <stdver.h>
  | 
