From 65f66e14c2d63a53965d8f5b4b9084d12555f109 Mon Sep 17 00:00:00 2001 From: JLGG Date: Wed, 22 Jul 2015 04:50:05 +0200 Subject: [PATCH 01/22] forward method: remove notify token --- yowsup/layers/protocol_messages/protocolentities/message.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yowsup/layers/protocol_messages/protocolentities/message.py b/yowsup/layers/protocol_messages/protocolentities/message.py index 4d10b46ff..c739027f7 100644 --- a/yowsup/layers/protocol_messages/protocolentities/message.py +++ b/yowsup/layers/protocol_messages/protocolentities/message.py @@ -104,10 +104,11 @@ def __str__(self): def ack(self, read=False): return OutgoingReceiptProtocolEntity(self.getId(), self.getFrom(), read, participant=self.getParticipant()) - def forward(self, to, _id = None): + def forward(self, to, _id = None, notify = None): OutgoingMessage = deepcopy(self) OutgoingMessage.to = to OutgoingMessage._from = None + OutgoingMessage.notify = notify OutgoingMessage._id = self._generateId() if _id is None else _id OutgoingMessage.participant = None # very strange issue with group messages otherwise return OutgoingMessage From ecf78ef7fb94fc9e5b0ee1776aca11a2ad0e1684 Mon Sep 17 00:00:00 2001 From: JLGG Date: Wed, 29 Jul 2015 17:14:19 +0200 Subject: [PATCH 02/22] notify, retry, t, offline removed from outgoingmessage at toProtocolTreeNode level --- .../protocolentities/message.py | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/yowsup/layers/protocol_messages/protocolentities/message.py b/yowsup/layers/protocol_messages/protocolentities/message.py index c739027f7..98e9f71c5 100644 --- a/yowsup/layers/protocol_messages/protocolentities/message.py +++ b/yowsup/layers/protocol_messages/protocolentities/message.py @@ -55,24 +55,21 @@ def toProtocolTreeNode(self): "id" : self._id, } - if not self.isOutgoing(): - attribs["t"] = str(self.timestamp) - - if self.offline is not None: - attribs["offline"] = "1" if self.offline else "0" - if self.isOutgoing(): attribs["to"] = self.to else: attribs["from"] = self._from - if self.notify: - attribs["notify"] = self.notify + attribs["t"] = str(self.timestamp) - if self.retry: - attribs["retry"] = str(self.retry) - if self.participant: - attribs["participant"] = self.participant + if self.offline is not None: + attribs["offline"] = "1" if self.offline else "0" + if self.notify: + attribs["notify"] = self.notify + if self.retry: + attribs["retry"] = str(self.retry) + if self.participant: + attribs["participant"] = self.participant xNode = None @@ -104,13 +101,11 @@ def __str__(self): def ack(self, read=False): return OutgoingReceiptProtocolEntity(self.getId(), self.getFrom(), read, participant=self.getParticipant()) - def forward(self, to, _id = None, notify = None): + def forward(self, to, _id = None): OutgoingMessage = deepcopy(self) OutgoingMessage.to = to OutgoingMessage._from = None - OutgoingMessage.notify = notify OutgoingMessage._id = self._generateId() if _id is None else _id - OutgoingMessage.participant = None # very strange issue with group messages otherwise return OutgoingMessage @staticmethod From e9b438bdd7dddf879361631f42ede90b3554c3f7 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 27 Jul 2015 01:32:20 +0200 Subject: [PATCH 03/22] Layer interfaces initial commit --- yowsup/demos/cli/layer.py | 21 ++++++------ yowsup/demos/cli/stack.py | 8 ++--- yowsup/layers/__init__.py | 16 +++++++++ yowsup/layers/auth/layer_authentication.py | 20 ++++++----- .../auth/layer_interface_authentication.py | 5 +++ yowsup/layers/network/layer.py | 33 ++++++++++++------- yowsup/layers/network/layer_interface.py | 10 ++++++ yowsup/stacks/yowstack.py | 10 ++++++ 8 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 yowsup/layers/auth/layer_interface_authentication.py create mode 100644 yowsup/layers/network/layer_interface.py diff --git a/yowsup/demos/cli/layer.py b/yowsup/demos/cli/layer.py index 1754c11b2..186eb2e38 100644 --- a/yowsup/demos/cli/layer.py +++ b/yowsup/demos/cli/layer.py @@ -48,6 +48,7 @@ def __init__(self): self.username = None self.sendReceipts = True self.disconnectAction = self.__class__.DISCONNECT_ACTION_PROMPT + self.credentials = None #add aliases to make it user to use commands. for example you can then do: # /message send foobar "HI" @@ -77,6 +78,9 @@ def normalizeJid(self, number): return "%s@s.whatsapp.net" % number + def setCredentials(self, username, password): + self.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(username, password) + def onEvent(self, layerEvent): if layerEvent.getName() == self.__class__.EVENT_START: self.startInput() @@ -406,23 +410,20 @@ def contacts_sync(self, contacts): @clicmd("Disconnect") def disconnect(self): if self.assertConnected(): + self.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT)) @clicmd("Quick login") def L(self): - return self.login(*self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)) - - @clicmd("Login to WhatsApp", 0) - def login(self, username, b64password): - if self.connected: return self.output("Already connected, disconnect first") + self.getLayerInterface(YowNetworkLayer).connect() + return True - self.getStack().setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, (username, b64password)) - connectEvent = YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT) - self.broadcastEvent(connectEvent) - return True #prompt will wait until notified - + @clicmd("Login to WhatsApp", 0) + def login(self, username, b64password): + self.setCredentials(username, b64password) + return self.L() ######## receive ######### diff --git a/yowsup/demos/cli/stack.py b/yowsup/demos/cli/stack.py index de06a2d59..a556306e8 100644 --- a/yowsup/demos/cli/stack.py +++ b/yowsup/demos/cli/stack.py @@ -1,9 +1,8 @@ -from yowsup.stacks import YowStack, YowStackBuilder +from yowsup.stacks import YowStackBuilder from .layer import YowsupCliLayer from yowsup.layers.auth import AuthError from yowsup.layers import YowLayerEvent -from yowsup import env -from yowsup.env import S40YowsupEnv +from yowsup.layers.auth import YowAuthenticationProtocolLayer import sys class YowsupCliStack(object): @@ -15,7 +14,8 @@ def __init__(self, credentials, encryptionEnabled = True): .push(YowsupCliLayer)\ .build() - self.stack.setCredentials(credentials) + # self.stack.setCredentials(credentials) + self.stack.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(credentials) def start(self): print("Yowsup Cli client\n==================\nType /help for available commands\n") diff --git a/yowsup/layers/__init__.py b/yowsup/layers/__init__.py index 8c86d4843..4bfc6f52c 100644 --- a/yowsup/layers/__init__.py +++ b/yowsup/layers/__init__.py @@ -33,6 +33,13 @@ class YowLayer(object): def __init__(self): self.setLayers(None, None) + self.interface = None + + def getInterface(self): + return self.interface + + def getLayerInterface(self, YowLayerClass): + return self.__stack.getLayerInterface(YowLayerClass) def setStack(self, stack): self.__stack = stack @@ -149,6 +156,11 @@ def __init__(self, sublayers = None): s.emitEvent = self.subEmitEvent + def getLayerInterface(self, YowLayerClass): + for s in self.sublayers: + if s.__class__ == YowLayerClass: + return s + def setStack(self, stack): super(YowParallelLayer, self).setStack(stack) for s in self.sublayers: @@ -182,6 +194,10 @@ def onEvent(self, yowLayerEvent): def __str__(self): return " - ".join([l.__str__() for l in self.sublayers]) +class YowLayerInterface(object): + def __init__(self, layer): + self._layer = layer + class YowLayerTest(unittest.TestCase): def __init__(self, *args): diff --git a/yowsup/layers/auth/layer_authentication.py b/yowsup/layers/auth/layer_authentication.py index 1d239424a..2bfe186bc 100644 --- a/yowsup/layers/auth/layer_authentication.py +++ b/yowsup/layers/auth/layer_authentication.py @@ -1,4 +1,4 @@ -from yowsup.layers import YowLayer, YowLayerEvent, YowProtocolLayer +from yowsup.layers import YowLayerEvent, YowProtocolLayer from .keystream import KeyStream from yowsup.common.tools import TimeTools from .layer_crypt import YowCryptLayer @@ -6,6 +6,7 @@ from .autherror import AuthError from .protocolentities import * from yowsup.common.tools import StorageTools +from .layer_interface_authentication import YowAuthenticationProtocolLayerInterface import base64 class YowAuthenticationProtocolLayer(YowProtocolLayer): EVENT_LOGIN = "org.openwhatsapp.yowsup.event.auth.login" @@ -22,29 +23,30 @@ def __init__(self): "stream:error": (self.handleStreamError, None), } super(YowAuthenticationProtocolLayer, self).__init__(handleMap) - self.credentials = None + self.interface = YowAuthenticationProtocolLayerInterface(self) + self.credentials = None #left for backwards-compat + self._credentials = None #new style set def __str__(self): return "Authentication Layer" - def __getCredentials(self): - u, pb64 = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS) + def __getCredentials(self, credentials = None): + u, pb64 = credentials or self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS) if type(pb64) is str: pb64 = pb64.encode() password = base64.b64decode(pb64) return (u, bytearray(password)) + def setCredentials(self, credentials): + self._credentials = self.__getCredentials(credentials) + def onEvent(self, event): if event.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: self.login() - elif event.getName() == YowNetworkLayer.EVENT_STATE_CONNECT: - self.credentials = self.__getCredentials() - if not self.credentials: - raise AuthError("Auth stopped connection signal as no credentials have been set") ## general methods def login(self): - + self.credentials = self._credentials or self.__getCredentials() self._sendFeatures() self._sendAuth() diff --git a/yowsup/layers/auth/layer_interface_authentication.py b/yowsup/layers/auth/layer_interface_authentication.py new file mode 100644 index 000000000..5c7f2a763 --- /dev/null +++ b/yowsup/layers/auth/layer_interface_authentication.py @@ -0,0 +1,5 @@ +from yowsup.layers import YowLayerInterface + +class YowAuthenticationProtocolLayerInterface(YowLayerInterface): + def setCredentials(self, phone, password): + self._layer.setCredentials(phone, password) \ No newline at end of file diff --git a/yowsup/layers/network/layer.py b/yowsup/layers/network/layer.py index db5d468ca..35f255806 100644 --- a/yowsup/layers/network/layer.py +++ b/yowsup/layers/network/layer.py @@ -1,5 +1,6 @@ from yowsup.layers import YowLayer, YowLayerEvent from yowsup.common.http.httpproxy import HttpProxy +from yowsup.layers.network.layer_interface import YowNetworkLayerInterface import asyncore, socket, logging logger = logging.getLogger(__name__) @@ -19,6 +20,7 @@ class YowNetworkLayer(YowLayer, asyncore.dispatcher_with_send): def __init__(self): YowLayer.__init__(self) + self.interface = YowNetworkLayerInterface(self) asyncore.dispatcher.__init__(self) httpProxy = HttpProxy.getFromEnviron() proxyHandler = None @@ -34,20 +36,29 @@ def onConnect(): def onEvent(self, ev): if ev.getName() == YowNetworkLayer.EVENT_STATE_CONNECT: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.out_buffer = bytearray() - endpoint = self.getProp(self.__class__.PROP_ENDPOINT) - logger.debug("Connecting to %s:%s" % endpoint) - if self.proxyHandler != None: - logger.debug("HttpProxy connect: %s:%d" % endpoint) - self.proxyHandler.connect(self, endpoint) - else: - self.connect(endpoint) + self.createConnection() return True elif ev.getName() == YowNetworkLayer.EVENT_STATE_DISCONNECT: - self.handle_close(ev.getArg("reason") or "Requested") + self.destroyConnection(ev.getArg("reason")) return True + def createConnection(self): + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.out_buffer = bytearray() + endpoint = self.getProp(self.__class__.PROP_ENDPOINT) + logger.debug("Connecting to %s:%s" % endpoint) + if self.proxyHandler != None: + logger.debug("HttpProxy connect: %s:%d" % endpoint) + self.proxyHandler.connect(self, endpoint) + else: + self.connect(endpoint) + + def destroyConnection(self, reason = None): + self.handle_close(reason or "Requested") + + def getStatus(self): + return self.connected + def handle_connect(self): if self.proxyHandler != None: logger.debug("HttpProxy handle connect") @@ -80,4 +91,4 @@ def receive(self, data): self.toUpper(data) def __str__(self): - return "Network Layer" + return "Network Layer" \ No newline at end of file diff --git a/yowsup/layers/network/layer_interface.py b/yowsup/layers/network/layer_interface.py new file mode 100644 index 000000000..a75594ebf --- /dev/null +++ b/yowsup/layers/network/layer_interface.py @@ -0,0 +1,10 @@ +from yowsup.layers import YowLayerInterface +class YowNetworkLayerInterface(YowLayerInterface): + def connect(self): + self._layer.createConnection() + + def disconnect(self): + self._layer.destroyConnection() + + def getStatus(self): + return self._layer.getStatus() \ No newline at end of file diff --git a/yowsup/stacks/yowstack.py b/yowsup/stacks/yowstack.py index 324dbd508..ba0482f18 100644 --- a/yowsup/stacks/yowstack.py +++ b/yowsup/stacks/yowstack.py @@ -131,6 +131,16 @@ def __init__(self, stackClassesArr = None, reversed = True): self.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource()) + def getLayerInterface(self, YowLayerClass): + for inst in self.__stackInstances: + if inst.__class__ == YowLayerClass: + return inst.getInterface() + elif inst.__class__ == YowParallelLayer: + res = inst.getLayerInterface(YowLayerClass) + if res: + return res + + def setCredentials(self, credentials): self.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, credentials) From f61d6f1b06ebb7497cae749d445917c019afa447 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 27 Jul 2015 07:47:09 +0200 Subject: [PATCH 04/22] Added auth layer interface --- yowsup/layers/auth/layer_authentication.py | 4 ++++ yowsup/layers/auth/layer_interface_authentication.py | 5 ++++- yowsup/layers/interface/interface.py | 5 +---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/yowsup/layers/auth/layer_authentication.py b/yowsup/layers/auth/layer_authentication.py index 2bfe186bc..ae9901f82 100644 --- a/yowsup/layers/auth/layer_authentication.py +++ b/yowsup/layers/auth/layer_authentication.py @@ -40,6 +40,10 @@ def __getCredentials(self, credentials = None): def setCredentials(self, credentials): self._credentials = self.__getCredentials(credentials) + def getUsername(self, full = False): + if self._credentials: + return self._credentials[0] if not full else ("%s@s.whatsapp.net" % self._credentials[0]) + def onEvent(self, event): if event.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: self.login() diff --git a/yowsup/layers/auth/layer_interface_authentication.py b/yowsup/layers/auth/layer_interface_authentication.py index 5c7f2a763..49d72f668 100644 --- a/yowsup/layers/auth/layer_interface_authentication.py +++ b/yowsup/layers/auth/layer_interface_authentication.py @@ -2,4 +2,7 @@ class YowAuthenticationProtocolLayerInterface(YowLayerInterface): def setCredentials(self, phone, password): - self._layer.setCredentials(phone, password) \ No newline at end of file + self._layer.setCredentials(phone, password) + + def getUsername(self, full = False): + return self._layer.getUsername(full) \ No newline at end of file diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index 4d41e5c00..680715fb9 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -48,10 +48,7 @@ def processIqRegistry(self, entity): return False def getOwnJid(self, full = True): - jid = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0] - if jid: - return jid + "@s.whatsapp.net" if full else jid - return None + return self.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(full) def connect(self): loginEvent = YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT) From 2c34db52eb24c2a366854389542430cda15a41d7 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Sat, 8 Aug 2015 20:16:20 +0200 Subject: [PATCH 05/22] Single method for getting layer interface --- yowsup/layers/__init__.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/yowsup/layers/__init__.py b/yowsup/layers/__init__.py index 4bfc6f52c..a59954761 100644 --- a/yowsup/layers/__init__.py +++ b/yowsup/layers/__init__.py @@ -35,11 +35,8 @@ def __init__(self): self.setLayers(None, None) self.interface = None - def getInterface(self): - return self.interface - - def getLayerInterface(self, YowLayerClass): - return self.__stack.getLayerInterface(YowLayerClass) + def getLayerInterface(self, YowLayerClass = None): + return self.interface if YowLayerClass is None else self.__stack.getLayerInterface(YowLayerClass) def setStack(self, stack): self.__stack = stack From 67b16de15a6f0aafbb6a7d618b4c49d4b4c1bce6 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Sun, 9 Aug 2015 22:03:25 +0200 Subject: [PATCH 06/22] Fixed getLayerInterface call --- yowsup/stacks/yowstack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yowsup/stacks/yowstack.py b/yowsup/stacks/yowstack.py index ba0482f18..9e60ccf54 100644 --- a/yowsup/stacks/yowstack.py +++ b/yowsup/stacks/yowstack.py @@ -134,7 +134,7 @@ def __init__(self, stackClassesArr = None, reversed = True): def getLayerInterface(self, YowLayerClass): for inst in self.__stackInstances: if inst.__class__ == YowLayerClass: - return inst.getInterface() + return inst.getLayerInterface() elif inst.__class__ == YowParallelLayer: res = inst.getLayerInterface(YowLayerClass) if res: From 8bf19fe4313aefdebf80746d5dd82fa011d5a78b Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Sun, 9 Aug 2015 22:42:20 +0200 Subject: [PATCH 07/22] Can send data to layers via stack.send/receive Makes testing easier --- yowsup/stacks/yowstack.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/yowsup/stacks/yowstack.py b/yowsup/stacks/yowstack.py index 9e60ccf54..8a957226f 100644 --- a/yowsup/stacks/yowstack.py +++ b/yowsup/stacks/yowstack.py @@ -141,6 +141,12 @@ def getLayerInterface(self, YowLayerClass): return res + def send(self, data): + self.__stackInstances[-1].send(data) + + def receive(self, data): + self.__stackInstances[0].receive(data) + def setCredentials(self, credentials): self.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, credentials) From e569303277597fa3b09d29709d5bc192d05e61be Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Sun, 9 Aug 2015 23:18:08 +0200 Subject: [PATCH 08/22] Call super contructor from YowInterfaceLayer --- yowsup/layers/interface/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index 680715fb9..8b9783299 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -15,6 +15,7 @@ def __call__(self, fn): class YowInterfaceLayer(YowLayer): def __init__(self): + super(YowInterfaceLayer, self).__init__() self.callbacks = {} self.iqRegistry = {} members = inspect.getmembers(self, predicate=inspect.ismethod) From a7315ed27352957f2a7756cc161be2aabe8f46e1 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Wed, 12 Aug 2015 08:11:08 +0200 Subject: [PATCH 09/22] Fixed the switch to networklayer interface to connect --- yowsup/layers/auth/layer_authentication.py | 1 + yowsup/layers/auth/layer_crypt.py | 2 +- yowsup/layers/axolotl/layer.py | 4 ++-- yowsup/layers/interface/interface.py | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/yowsup/layers/auth/layer_authentication.py b/yowsup/layers/auth/layer_authentication.py index ae9901f82..10e536165 100644 --- a/yowsup/layers/auth/layer_authentication.py +++ b/yowsup/layers/auth/layer_authentication.py @@ -38,6 +38,7 @@ def __getCredentials(self, credentials = None): return (u, bytearray(password)) def setCredentials(self, credentials): + self.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, credentials) #keep for now self._credentials = self.__getCredentials(credentials) def getUsername(self, full = False): diff --git a/yowsup/layers/auth/layer_crypt.py b/yowsup/layers/auth/layer_crypt.py index f0e6e8762..9d7822670 100644 --- a/yowsup/layers/auth/layer_crypt.py +++ b/yowsup/layers/auth/layer_crypt.py @@ -13,7 +13,7 @@ def __init__(self): self.keys = (None,None) def onEvent(self, yowLayerEvent): - if yowLayerEvent.getName() == YowNetworkLayer.EVENT_STATE_CONNECT: + if yowLayerEvent.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: self.keys = (None,None) elif yowLayerEvent.getName() == YowCryptLayer.EVENT_KEYS_READY: self.keys = yowLayerEvent.getArg("keys") diff --git a/yowsup/layers/axolotl/layer.py b/yowsup/layers/axolotl/layer.py index 6088980be..5a3a86018 100644 --- a/yowsup/layers/axolotl/layer.py +++ b/yowsup/layers/axolotl/layer.py @@ -72,7 +72,7 @@ def isGenKeysState(self): def onEvent(self, yowLayerEvent): if yowLayerEvent.getName() == self.__class__.EVENT_PREKEYS_SET: self.sendKeys(fresh=False) - elif yowLayerEvent.getName() == YowNetworkLayer.EVENT_STATE_CONNECT: + elif yowLayerEvent.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: self.initStore() if self.isInitState(): self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True) @@ -86,7 +86,7 @@ def onEvent(self, yowLayerEvent): #no need to traverse it to upper layers? self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, False) self.state = self.__class__._STATE_HASKEYS - self.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) + self.getLayerInterface(YowNetworkLayer).connect() def send(self, node): if node.tag == "message" and node["type"] == "text" and node["to"] not in self.skipEncJids: diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index 8b9783299..be05a87a6 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -52,8 +52,7 @@ def getOwnJid(self, full = True): return self.getLayerInterface(YowAuthenticationProtocolLayer).getUsername(full) def connect(self): - loginEvent = YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT) - self.broadcastEvent(loginEvent) + self.getLayerInterface(YowNetworkLayer).connect() def disconnect(self): disconnectEvent = YowLayerEvent(YowNetworkLayer.EVENT_STATE_DISCONNECT) From 83958015b9fa9f37003c6b60678b02b7f8a7572a Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 00:43:41 +0200 Subject: [PATCH 10/22] Added receipt registery for receipt-> ack callback Send receipt from a YowInterfaceLayer using _sendReceipt(receiptEntity, onAckClb) --- yowsup/layers/interface/interface.py | 35 +++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index be05a87a6..04d210693 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -2,6 +2,8 @@ from yowsup.layers.protocol_iq.protocolentities import IqProtocolEntity from yowsup.layers.network import YowNetworkLayer from yowsup.layers.auth import YowAuthenticationProtocolLayer +from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity +from yowsup.layers.protocol_acks.protocolentities import IncomingAckProtocolEntity import inspect class ProtocolEntityCallback(object): @@ -18,6 +20,7 @@ def __init__(self): super(YowInterfaceLayer, self).__init__() self.callbacks = {} self.iqRegistry = {} + self.receiptsRegistry = {} members = inspect.getmembers(self, predicate=inspect.ismethod) for m in members: if hasattr(m[1], "callback"): @@ -30,6 +33,33 @@ def _sendIq(self, iqEntity, onSuccess = None, onError = None): self.iqRegistry[iqEntity.getId()] = (iqEntity, onSuccess, onError) self.toLower(iqEntity) + def _sendReceipt(self, outgoingReceiptProtocolEntity, onAck = None): + assert outgoingReceiptProtocolEntity.__class__ == OutgoingReceiptProtocolEntity,\ + "Excepted OutgoingReceiptProtocolEntity in _sendReceipt, got %s" % outgoingReceiptProtocolEntity.__class__ + self.receiptsRegistry[outgoingReceiptProtocolEntity.getId()] = (outgoingReceiptProtocolEntity, onAck) + self.toLower(outgoingReceiptProtocolEntity) + + def processReceiptsRegistry(self, incomingAckProtocolEntity): + ''' + entity: IncomingAckProtocolEntity + ''' + + if incomingAckProtocolEntity.__class__ != IncomingAckProtocolEntity: + return False + + receipt_id = incomingAckProtocolEntity.getId() + if receipt_id in self.receiptsRegistry: + originalReceiptEntity, ackClbk = self.receiptsRegistry[receipt_id] + del self.receiptsRegistry[receipt_id] + + if ackClbk: + ackClbk(incomingAckProtocolEntity, originalReceiptEntity) + + return True + + return False + + def processIqRegistry(self, entity): """ :type entity: IqProtocolEntity @@ -62,12 +92,11 @@ def send(self, data): self.toLower(data) def receive(self, entity): - if not self.processIqRegistry(entity): + if not self.processIqRegistry(entity) and not self.processReceiptsRegistry(entity): entityType = entity.getTag() if entityType in self.callbacks: self.callbacks[entityType](entity) - + def __str__(self): return "Interface Layer" - From 2a046f93297f9325f1d91fb3e6424b97c13d34e5 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 00:50:20 +0200 Subject: [PATCH 11/22] Removed invalid 't' attribute in outgoing receipt --- .../protocol_receipts/protocolentities/receipt_outgoing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py b/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py index ffdf43536..7f364581c 100644 --- a/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py +++ b/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py @@ -26,7 +26,7 @@ def setOutgoingData(self, to, read, participant, callId): self.read = read self.participant = participant self.callId = callId - + def toProtocolTreeNode(self): node = super(OutgoingReceiptProtocolEntity, self).toProtocolTreeNode() if self.read: @@ -38,7 +38,6 @@ def toProtocolTreeNode(self): node.addChild(offer) node.setAttribute("to", self.to) - node.setAttribute("t", str(int(time.time()))) return node From 9266a67c3e1368685fade9e4db7b3ecd3297ca6a Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 01:07:32 +0200 Subject: [PATCH 12/22] Handle DuplicateMessageException Don't crash, and force send delivery receipt from axolotl layer Won't forward to upper layer since we can't decrypt it again, upper layer should have saved it the first time Fixes #978 Axolotl: DuplicateMessageException Fixes #911 DuplicateMessageException --- yowsup/layers/axolotl/layer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yowsup/layers/axolotl/layer.py b/yowsup/layers/axolotl/layer.py index 5a3a86018..1654157da 100644 --- a/yowsup/layers/axolotl/layer.py +++ b/yowsup/layers/axolotl/layer.py @@ -4,6 +4,7 @@ from .store.sqlite.liteaxolotlstore import LiteAxolotlStore from axolotl.sessionbuilder import SessionBuilder from yowsup.layers.protocol_messages.protocolentities.message import MessageProtocolEntity +from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity from yowsup.layers.network.layer import YowNetworkLayer from yowsup.layers.auth.layer_authentication import YowAuthenticationProtocolLayer from axolotl.ecc.curve import Curve @@ -16,6 +17,7 @@ from .protocolentities import GetKeysIqProtocolEntity, ResultGetKeysIqProtocolEntity from axolotl.util.hexutil import HexUtil from axolotl.invalidmessageexception import InvalidMessageException +from axolotl.duplicatemessagexception import DuplicateMessageException from .protocolentities import EncryptNotification from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity from axolotl.invalidkeyidexception import InvalidKeyIdException @@ -228,8 +230,10 @@ def handleEncMessage(self, node): self.pendingIncomingMessages[node["from"]].append(node) self._sendIq(entity, lambda a, b: self.onGetKeysResult(a, b, self.processPendingIncomingMessages), self.onGetKeysError) - - + except DuplicateMessageException as e: + logger.error(e) + logger.warning("Going to send the delivery receipt myself !") + self.toLower(OutgoingReceiptProtocolEntity(node["id"], node["from"]).toProtocolTreeNode()) def handlePreKeyWhisperMessage(self, node): pkMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) From f7e789422be7fc81dd249d018f00a25ec58deaa0 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 11:32:58 +0200 Subject: [PATCH 13/22] Rollback invalid receipts registry for now --- yowsup/layers/interface/interface.py | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index 04d210693..a57347bb4 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -20,7 +20,7 @@ def __init__(self): super(YowInterfaceLayer, self).__init__() self.callbacks = {} self.iqRegistry = {} - self.receiptsRegistry = {} + # self.receiptsRegistry = {} members = inspect.getmembers(self, predicate=inspect.ismethod) for m in members: if hasattr(m[1], "callback"): @@ -33,31 +33,31 @@ def _sendIq(self, iqEntity, onSuccess = None, onError = None): self.iqRegistry[iqEntity.getId()] = (iqEntity, onSuccess, onError) self.toLower(iqEntity) - def _sendReceipt(self, outgoingReceiptProtocolEntity, onAck = None): - assert outgoingReceiptProtocolEntity.__class__ == OutgoingReceiptProtocolEntity,\ - "Excepted OutgoingReceiptProtocolEntity in _sendReceipt, got %s" % outgoingReceiptProtocolEntity.__class__ - self.receiptsRegistry[outgoingReceiptProtocolEntity.getId()] = (outgoingReceiptProtocolEntity, onAck) - self.toLower(outgoingReceiptProtocolEntity) - - def processReceiptsRegistry(self, incomingAckProtocolEntity): - ''' - entity: IncomingAckProtocolEntity - ''' - - if incomingAckProtocolEntity.__class__ != IncomingAckProtocolEntity: - return False - - receipt_id = incomingAckProtocolEntity.getId() - if receipt_id in self.receiptsRegistry: - originalReceiptEntity, ackClbk = self.receiptsRegistry[receipt_id] - del self.receiptsRegistry[receipt_id] - - if ackClbk: - ackClbk(incomingAckProtocolEntity, originalReceiptEntity) - - return True - - return False + # def _sendReceipt(self, outgoingReceiptProtocolEntity, onAck = None): + # assert outgoingReceiptProtocolEntity.__class__ == OutgoingReceiptProtocolEntity,\ + # "Excepted OutgoingReceiptProtocolEntity in _sendReceipt, got %s" % outgoingReceiptProtocolEntity.__class__ + # self.receiptsRegistry[outgoingReceiptProtocolEntity.getId()] = (outgoingReceiptProtocolEntity, onAck) + # self.toLower(outgoingReceiptProtocolEntity) + + # def processReceiptsRegistry(self, incomingAckProtocolEntity): + # ''' + # entity: IncomingAckProtocolEntity + # ''' + # + # if incomingAckProtocolEntity.__class__ != IncomingAckProtocolEntity: + # return False + # + # receipt_id = incomingAckProtocolEntity.getId() + # if receipt_id in self.receiptsRegistry: + # originalReceiptEntity, ackClbk = self.receiptsRegistry[receipt_id] + # del self.receiptsRegistry[receipt_id] + # + # if ackClbk: + # ackClbk(incomingAckProtocolEntity, originalReceiptEntity) + # + # return True + # + # return False def processIqRegistry(self, entity): @@ -92,7 +92,7 @@ def send(self, data): self.toLower(data) def receive(self, entity): - if not self.processIqRegistry(entity) and not self.processReceiptsRegistry(entity): + if not self.processIqRegistry(entity): entityType = entity.getTag() if entityType in self.callbacks: self.callbacks[entityType](entity) From 0ea3abdb7b6550a85f1767fc8cc133a4d68c943b Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 16:15:04 +0200 Subject: [PATCH 14/22] Don't crash on UntrustedIdentityException Will ignore the message. refs #829 --- yowsup/layers/axolotl/layer.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yowsup/layers/axolotl/layer.py b/yowsup/layers/axolotl/layer.py index 1654157da..586a90427 100644 --- a/yowsup/layers/axolotl/layer.py +++ b/yowsup/layers/axolotl/layer.py @@ -22,6 +22,7 @@ from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity from axolotl.invalidkeyidexception import InvalidKeyIdException from axolotl.nosessionexception import NoSessionException +from axolotl.untrustedidentityexception import UntrustedIdentityException from .protocolentities.receipt_outgoing_retry import RetryOutgoingReceiptProtocolEntity import binascii import sys @@ -235,6 +236,10 @@ def handleEncMessage(self, node): logger.warning("Going to send the delivery receipt myself !") self.toLower(OutgoingReceiptProtocolEntity(node["id"], node["from"]).toProtocolTreeNode()) + except UntrustedIdentityException as e: + logger.error(e) + logger.warning("Ignoring message with untrusted identity") + def handlePreKeyWhisperMessage(self, node): pkMessageProtocolEntity = EncryptedMessageProtocolEntity.fromProtocolTreeNode(node) From 6773ffd974c639069e7f4d720c5d063438250969 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 16:16:46 +0200 Subject: [PATCH 15/22] Fixed interface not forwarding to upper layers unhandled protocolentities --- yowsup/layers/interface/interface.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yowsup/layers/interface/interface.py b/yowsup/layers/interface/interface.py index a57347bb4..c957a5b7d 100644 --- a/yowsup/layers/interface/interface.py +++ b/yowsup/layers/interface/interface.py @@ -96,6 +96,8 @@ def receive(self, entity): entityType = entity.getTag() if entityType in self.callbacks: self.callbacks[entityType](entity) + else: + self.toUpper(entity) def __str__(self): From 8844013638d1dd6291d13bb309cf2a8c48f51879 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 16:18:30 +0200 Subject: [PATCH 16/22] Allow setting props on stackbuilder Stackbuilder will then pass those props to the instantiated stack Fixes inability to getProp inside a layer's constructor --- yowsup/stacks/yowstack.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/yowsup/stacks/yowstack.py b/yowsup/stacks/yowstack.py index 8a957226f..f707cdb7f 100644 --- a/yowsup/stacks/yowstack.py +++ b/yowsup/stacks/yowstack.py @@ -42,6 +42,10 @@ class YowStackBuilder(object): def __init__(self): self.layers = () + self._props = {} + + def setProp(self, key, value): + self._props[key] = value def pushDefaultLayers(self, axolotl = False): defaultLayers = YowStackBuilder.getDefaultLayers(axolotl) @@ -57,7 +61,7 @@ def pop(self): return self def build(self): - return YowStack(self.layers, reversed = False) + return YowStack(self.layers, reversed = False, props = self._props) @staticmethod def getDefaultLayers(axolotl = False, groups = True, media = True, privacy = True, profiles = True): @@ -119,16 +123,16 @@ class YowStack(object): __stack = [] __stackInstances = [] __detachedQueue = Queue.Queue() - def __init__(self, stackClassesArr = None, reversed = True): + def __init__(self, stackClassesArr = None, reversed = True, props = None): stackClassesArr = stackClassesArr or () self.__stack = stackClassesArr[::-1] if reversed else stackClassesArr self.__stackInstances = [] - self._construct() - self._props = {} + self._props = props or {} self.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[random.randint(0,len(YowConstants.ENDPOINTS)-1)]) self.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN) self.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource()) + self._construct() def getLayerInterface(self, YowLayerClass): @@ -218,4 +222,3 @@ def _construct(self): def getLayer(self, layerIndex): return self.__stackInstances[layerIndex] - From d15a900abf1cfec5903e8283cf3e6589c91bd583 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 17 Aug 2015 20:43:01 +0200 Subject: [PATCH 17/22] Support sending receipt for multiple messages --- .../protocolentities/receipt_outgoing.py | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py b/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py index 7f364581c..33a11d246 100644 --- a/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py +++ b/yowsup/layers/protocol_receipts/protocolentities/receipt_outgoing.py @@ -13,20 +13,39 @@ class OutgoingReceiptProtocolEntity(ReceiptProtocolEntity): read - INCOMING - + multiple items: + + + + + + ''' - def __init__(self, _id, to, read = False, participant = None, callId = None): - super(OutgoingReceiptProtocolEntity, self).__init__(_id) - self.setOutgoingData(to, read, participant, callId) - def setOutgoingData(self, to, read, participant, callId): + def __init__(self, messageIds, to, read = False, participant = None, callId = None): + if type(messageIds) in (list, tuple): + if len(messageIds) > 1: + receiptId = self._generateId() + else: + receiptId = messageIds[0] + else: + receiptId = messageIds + messageIds = [messageIds] + + super(OutgoingReceiptProtocolEntity, self).__init__(receiptId) + self.setOutgoingData(messageIds, to, read, participant, callId) + + def setOutgoingData(self, messageIds, to, read, participant, callId): + self.messageIds = messageIds self.to = to self.read = read self.participant = participant self.callId = callId + def getMessageIds(self): + return self.messageIds + def toProtocolTreeNode(self): node = super(OutgoingReceiptProtocolEntity, self).toProtocolTreeNode() if self.read: @@ -39,6 +58,11 @@ def toProtocolTreeNode(self): node.setAttribute("to", self.to) + if len(self.messageIds) > 1: + listNode = ProtocolTreeNode("list") + listNode.addChildren([ProtocolTreeNode("item", {"id": mId}) for mId in self.messageIds]) + node.addChild(listNode) + return node def __str__(self): @@ -46,13 +70,21 @@ def __str__(self): out += "To: \n%s" % self.to if self.read: out += "Type: \n%s" % "read" + out += "For: \n%s" % self.messageIds return out @staticmethod def fromProtocolTreeNode(node): + listNode = node.getChild("list") + messageIds = [] + if listNode: + messageIds = [child["id"] for child in listNode.getChildren()] + else: + messageIds = [node["id"]] + return OutgoingReceiptProtocolEntity( - node.getAttributeValue("id"), - node.getAttributeValue("to"), - node.getAttributeValue("type"), - node.getAttributeValue("participant") + messageIds, + node["to"], + node["type"] == "read", + node["participant"] ) From 66566cd54161a3fb71ade6c538c1c35d82a1fe5a Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Tue, 18 Aug 2015 01:07:06 +0200 Subject: [PATCH 18/22] Don't panic on try send something when offline --- yowsup/layers/axolotl/layer.py | 35 ++++++++++++++++++++++------------ yowsup/layers/network/layer.py | 13 ++++++++----- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/yowsup/layers/axolotl/layer.py b/yowsup/layers/axolotl/layer.py index 586a90427..732211f67 100644 --- a/yowsup/layers/axolotl/layer.py +++ b/yowsup/layers/axolotl/layer.py @@ -49,23 +49,33 @@ def __init__(self): self.skipEncJids = [] self.v2Jids = [] #people we're going to send v2 enc messages + @property + def store(self): + if self._store is None: + self.store = LiteAxolotlStore( + StorageTools.constructPath( + self.getProp( + YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0], + self.__class__._DB + ) + ) + self.state = self.__class__._STATE_HASKEYS if self.store.getLocalRegistrationId() is not None \ + else self.__class__._STATE_INIT + + return self._store + + @store.setter + def store(self, store): + self._store = store + def __str__(self): return "Axolotl Layer" ### store and state - def initStore(self): - self.store = LiteAxolotlStore( - StorageTools.constructPath( - self.getProp( - YowAuthenticationProtocolLayer.PROP_CREDENTIALS)[0], - self.__class__._DB - ) - ) - self.state = self.__class__._STATE_HASKEYS if self.store.getLocalRegistrationId() is not None \ - else self.__class__._STATE_INIT + def isInitState(self): - return self.state == self.__class__._STATE_INIT + return self.store == None or self.state == self.__class__._STATE_INIT def isGenKeysState(self): return self.state == self.__class__._STATE_GENKEYS @@ -76,7 +86,6 @@ def onEvent(self, yowLayerEvent): if yowLayerEvent.getName() == self.__class__.EVENT_PREKEYS_SET: self.sendKeys(fresh=False) elif yowLayerEvent.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: - self.initStore() if self.isInitState(): self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True) elif yowLayerEvent.getName() == YowAuthenticationProtocolLayer.EVENT_AUTHED: @@ -90,6 +99,8 @@ def onEvent(self, yowLayerEvent): self.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, False) self.state = self.__class__._STATE_HASKEYS self.getLayerInterface(YowNetworkLayer).connect() + else: + self.store = None def send(self, node): if node.tag == "message" and node["type"] == "text" and node["to"] not in self.skipEncJids: diff --git a/yowsup/layers/network/layer.py b/yowsup/layers/network/layer.py index 35f255806..168a6067a 100644 --- a/yowsup/layers/network/layer.py +++ b/yowsup/layers/network/layer.py @@ -33,7 +33,7 @@ def onConnect(): proxyHandler = httpProxy.handler() proxyHandler.onConnect = onConnect self.proxyHandler = proxyHandler - + def onEvent(self, ev): if ev.getName() == YowNetworkLayer.EVENT_STATE_CONNECT: self.createConnection() @@ -60,6 +60,7 @@ def getStatus(self): return self.connected def handle_connect(self): + self.connected = True if self.proxyHandler != None: logger.debug("HttpProxy handle connect") self.proxyHandler.send(self) @@ -67,10 +68,11 @@ def handle_connect(self): self.emitEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECTED)) def handle_close(self, reason = "Connection Closed"): + self.connected = False logger.debug("Disconnected, reason: %s" % reason) self.emitEvent(YowLayerEvent(self.__class__.EVENT_STATE_DISCONNECTED, reason = reason, detached=True)) self.close() - + def handle_error(self): raise @@ -84,11 +86,12 @@ def handle_read(self): self.receive(data) def send(self, data): - self.out_buffer = self.out_buffer + data - self.initiate_send() + if self.connected: + self.out_buffer = self.out_buffer + data + self.initiate_send() def receive(self, data): self.toUpper(data) def __str__(self): - return "Network Layer" \ No newline at end of file + return "Network Layer" From 75075406097b60b4b889bea2ab7f33f8373bc5cf Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 31 Aug 2015 07:05:16 +0200 Subject: [PATCH 19/22] Fixed set credentials backwards compat after new auth interface --- yowsup/demos/cli/stack.py | 4 ++-- yowsup/layers/auth/layer_authentication.py | 5 ++++- yowsup/stacks/yowstack.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/yowsup/demos/cli/stack.py b/yowsup/demos/cli/stack.py index a556306e8..715110a8e 100644 --- a/yowsup/demos/cli/stack.py +++ b/yowsup/demos/cli/stack.py @@ -15,7 +15,7 @@ def __init__(self, credentials, encryptionEnabled = True): .build() # self.stack.setCredentials(credentials) - self.stack.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(credentials) + self.stack.setCredentials(credentials) def start(self): print("Yowsup Cli client\n==================\nType /help for available commands\n") @@ -27,4 +27,4 @@ def start(self): print("Auth Error, reason %s" % e) except KeyboardInterrupt: print("\nYowsdown") - sys.exit(0) \ No newline at end of file + sys.exit(0) diff --git a/yowsup/layers/auth/layer_authentication.py b/yowsup/layers/auth/layer_authentication.py index 10e536165..af198d00c 100644 --- a/yowsup/layers/auth/layer_authentication.py +++ b/yowsup/layers/auth/layer_authentication.py @@ -44,6 +44,9 @@ def setCredentials(self, credentials): def getUsername(self, full = False): if self._credentials: return self._credentials[0] if not full else ("%s@s.whatsapp.net" % self._credentials[0]) + else: + prop = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS) + return prop[0] if prop else None def onEvent(self, event): if event.getName() == YowNetworkLayer.EVENT_STATE_CONNECTED: @@ -109,7 +112,7 @@ def _sendResponse(self,nonce): responseEntity = ResponseProtocolEntity(authBlob) #to prevent enr whole response - self.broadcastEvent(YowLayerEvent(YowCryptLayer.EVENT_KEYS_READY, keys = (inputKey, None))) + self.broadcastEvent(YowLayerEvent(YowCryptLayer.EVENT_KEYS_READY, keys = (inputKey, None))) self.entityToLower(responseEntity) self.broadcastEvent(YowLayerEvent(YowCryptLayer.EVENT_KEYS_READY, keys = (inputKey, outputKey))) #YowCryptLayer.setProp("outputKey", outputKey) diff --git a/yowsup/stacks/yowstack.py b/yowsup/stacks/yowstack.py index f707cdb7f..c17a0850c 100644 --- a/yowsup/stacks/yowstack.py +++ b/yowsup/stacks/yowstack.py @@ -152,7 +152,7 @@ def receive(self, data): self.__stackInstances[0].receive(data) def setCredentials(self, credentials): - self.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, credentials) + self.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(credentials) def addLayer(self, layerClass): self.__stack.push(layerClass) From 75af998622cd8deff45d7bd2d60c9a5c04a446cf Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 7 Sep 2015 00:15:38 +0200 Subject: [PATCH 20/22] Updated s40 env to 2.12.96 --- yowsup/env/env_s40.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yowsup/env/env_s40.py b/yowsup/env/env_s40.py index 5b312b2c1..8ef3d6602 100644 --- a/yowsup/env/env_s40.py +++ b/yowsup/env/env_s40.py @@ -2,11 +2,11 @@ import base64 import hashlib class S40YowsupEnv(YowsupEnv): - _VERSION = "2.12.89" + _VERSION = "2.12.96" _OS_NAME= "S40" _OS_VERSION = "14.26" _DEVICE_NAME = "Nokia302" - _TOKEN_STRING = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1435688727801{phone}" + _TOKEN_STRING = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1439921717185{phone}" _AXOLOTL = True def getVersion(self): @@ -34,4 +34,3 @@ def getUserAgent(self): OS_VERSION = self.getOSVersion(), DEVICE_NAME = self.getDeviceName() ) - From e485abf88aa2b5d2d45fc742a97de45d7083d152 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 7 Sep 2015 00:21:17 +0200 Subject: [PATCH 21/22] Enable E2E enc by default, opt-out via -M --- yowsup-cli | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/yowsup-cli b/yowsup-cli index 7a29bb64f..ad27c5e7b 100755 --- a/yowsup-cli +++ b/yowsup-cli @@ -205,8 +205,7 @@ class DemosArgParser(YowArgParser): credentialsOpts.add_argument("-c", "--config", action="store", help = "Path to config file containing authentication info. For more info about config format use --help-config") - configGroup.add_argument("-m", "--moxie", action="store_true", help="Enable experimental support for the" - " new WhatsApp encryption") + configGroup.add_argument("-M", "--unmoxie", action="store_true", help="Disable E2E Encryption") cmdopts = self.add_argument_group("Command line interface demo") cmdopts.add_argument('-y', '--yowsup', action = "store_true", help = "Start the Yowsup command line client") @@ -224,9 +223,6 @@ class DemosArgParser(YowArgParser): def process(self): super(DemosArgParser, self).process() - if self.args["moxie"]: - logger.warning("--moxie/-m is deprecated and will be removed soon as e2e encryption is now almost mandatory.") - if self.args["yowsup"]: self.startCmdline() elif self.args["echo"]: @@ -255,7 +251,7 @@ class DemosArgParser(YowArgParser): if not credentials: print("Error: You must specify a configuration method") sys.exit(1) - stack = cli.YowsupCliStack(credentials, self.args["moxie"]) + stack = cli.YowsupCliStack(credentials, not self.args["unmoxie"]) stack.start() def startEcho(self): @@ -265,7 +261,7 @@ class DemosArgParser(YowArgParser): print("Error: You must specify a configuration method") sys.exit(1) try: - stack = echoclient.YowsupEchoStack(credentials, self.args["moxie"]) + stack = echoclient.YowsupEchoStack(credentials, not self.args["unmoxie"]) stack.start() except KeyboardInterrupt: print("\nYowsdown") @@ -280,7 +276,7 @@ class DemosArgParser(YowArgParser): try: stack = sendclient.YowsupSendStack(credentials, [([self.args["send"][0], self.args["send"][1]])], - self.args["moxie"]) + not self.args["unmoxie"]) stack.start() except KeyboardInterrupt: print("\nYowsdown") @@ -293,7 +289,7 @@ class DemosArgParser(YowArgParser): print("Error: You must specify a configuration method") sys.exit(1) try: - stack = contacts.YowsupSyncStack(credentials,self.args["sync"].split(','),self.args["moxie"]) + stack = contacts.YowsupSyncStack(credentials,self.args["sync"].split(','), not self.args["unmoxie"]) stack.start() except KeyboardInterrupt: print("\nYowsdown") @@ -326,4 +322,3 @@ if __name__ == "__main__": parser = modeDict[mode]() if not parser.process(): parser.print_help() - From 5a2f794510cd04ed49bb045eb39c82ac01b9f620 Mon Sep 17 00:00:00 2001 From: Tarek Galal Date: Mon, 7 Sep 2015 00:31:24 +0200 Subject: [PATCH 22/22] Bumped to 2.4/2.013 --- README.md | 5 ++++- yowsup-cli | 2 +- yowsup/__init__.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eee64ae07..46a374d0b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,10 @@ -## Updates (August 01, 2015) +## Updates (September 07, 2015) +Yowsup v2.4 is out, See [release notes](https://github.com/tgalal/yowsup/releases/tag/v2.4) + +### Updates (August 01, 2015) Yowsup v2.3.185 is out, contains fixes in axolotl integration. See [release notes](https://github.com/tgalal/yowsup/releases/tag/v2.3.185) ### Updates (July 27, 2015) diff --git a/yowsup-cli b/yowsup-cli index ad27c5e7b..010cece54 100755 --- a/yowsup-cli +++ b/yowsup-cli @@ -1,5 +1,5 @@ #!/usr/bin/env python -__version__ = "2.0.12" +__version__ = "2.0.13" __author__ = "Tarek Galal" import sys, argparse, yowsup, logging diff --git a/yowsup/__init__.py b/yowsup/__init__.py index d8d7cfc06..c9bd9263a 100644 --- a/yowsup/__init__.py +++ b/yowsup/__init__.py @@ -1,2 +1,2 @@ -__version__ = "2.3.185" +__version__ = "2.4" __author__ = "Tarek Galal"