Skip to content

Commit

Permalink
Merge branch 'release/2.5.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
tgalal committed May 22, 2016
2 parents fa6bf89 + 5d1f26a commit f510d44
Show file tree
Hide file tree
Showing 59 changed files with 2,882 additions and 1,236 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include yowsup/common/mime.types
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import platform
import sys

deps = ['python-dateutil', 'argparse', 'python-axolotl>=0.1.7']
deps = ['python-dateutil', 'argparse', 'python-axolotl>=0.1.35', 'six']

if sys.version_info < (2,7):
deps += ['importlib']
Expand Down Expand Up @@ -33,6 +33,7 @@
#long_description=long_description,
packages= find_packages(),
include_package_data=True,
data_files = [('yowsup/common', ['yowsup/common/mime.types'])],
platforms='any',
#test_suite='',
classifiers = [
Expand Down
2 changes: 1 addition & 1 deletion yowsup/common/optionalmodules.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, failMessage = None, require = False):
class AxolotlOptionalModule(OptionalModule):
def __init__(self, failMessage = None, require = False):
super(AxolotlOptionalModule, self).__init__("axolotl",
failmessage=failMessage,
failMessage=failMessage,
require=require)

if __name__ == "__main__":
Expand Down
10 changes: 6 additions & 4 deletions yowsup/common/tools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time,datetime,re, hashlib
import calendar
from dateutil import tz
import os
from .constants import YowConstants
Expand Down Expand Up @@ -107,9 +108,8 @@ def utcToLocal(dt):

@staticmethod
def utcTimestamp():
#utc = tz.gettz('UTC')
utcNow = datetime.datetime.utcnow()
return TimeTools.datetimeToTimestamp(utcNow)
return calendar.timegm(utcNow.timetuple())

@staticmethod
def datetimeToTimestamp(dt):
Expand Down Expand Up @@ -152,8 +152,10 @@ def generatePreviewFromImage(image):
class MimeTools:
MIME_FILE = os.path.join(os.path.dirname(__file__), 'mime.types')
mimetypes.init() # Load default mime.types
mimetypes.init([MIME_FILE]) # Append whatsapp mime.types
decode_hex = codecs.getdecoder("hex_codec")
try:
mimetypes.init([MIME_FILE]) # Append whatsapp mime.types
except exception as e:
logger.warning("Mime types supported can't be read. System mimes will be used. Cause: " + e.message)

@staticmethod
def getMIME(filepath):
Expand Down
11 changes: 1 addition & 10 deletions yowsup/demos/cli/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
import datetime
import os
import logging
from yowsup.layers.protocol_receipts.protocolentities import *
from yowsup.layers.protocol_groups.protocolentities import *
from yowsup.layers.protocol_presence.protocolentities import *
from yowsup.layers.protocol_messages.protocolentities import *
from yowsup.layers.protocol_acks.protocolentities import *
from yowsup.layers.protocol_ib.protocolentities import *
from yowsup.layers.protocol_iq.protocolentities import *
from yowsup.layers.protocol_contacts.protocolentities import *
Expand All @@ -25,7 +23,6 @@
from yowsup.common.optionalmodules import PILOptionalModule, AxolotlOptionalModule

logger = logging.getLogger(__name__)

class YowsupCliLayer(Cli, YowInterfaceLayer):
PROP_RECEIPT_AUTO = "org.openwhatsapp.yowsup.prop.cli.autoreceipt"
PROP_RECEIPT_KEEPALIVE = "org.openwhatsapp.yowsup.prop.cli.keepalive"
Expand Down Expand Up @@ -78,6 +75,7 @@ def jidToAlias(self, jid):
def setCredentials(self, username, password):
self.getLayerInterface(YowAuthenticationProtocolLayer).setCredentials(username, password)

return "%[email protected]" % username

@EventCallback(EVENT_START)
def onStart(self, layerEvent):
Expand Down Expand Up @@ -343,13 +341,6 @@ def keys_get(self, jids):
entity = GetKeysIqProtocolEntity(jids)
self.toLower(entity)

@clicmd("Send prekeys")
def keys_set(self):
with AxolotlOptionalModule(failMessage = self.__class__.FAIL_OPT_AXOLOTL) as axoOptMod:
from yowsup.layers.axolotl import YowAxolotlLayer
if self.assertConnected():
self.broadcastEvent(YowLayerEvent(YowAxolotlLayer.EVENT_PREKEYS_SET))

@clicmd("Send init seq")
def seq(self):
priv = PrivacyListIqProtocolEntity()
Expand Down
3 changes: 2 additions & 1 deletion yowsup/demos/cli/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from .layer import YowsupCliLayer
from yowsup.layers.auth import AuthError
from yowsup.layers import YowLayerEvent
from yowsup.layers.auth import YowAuthenticationProtocolLayer
from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST
import sys

class YowsupCliStack(object):
Expand All @@ -16,6 +16,7 @@ def __init__(self, credentials, encryptionEnabled = True):

# self.stack.setCredentials(credentials)
self.stack.setCredentials(credentials)
self.stack.setProp(PROP_IDENTITY_AUTOTRUST, True)

def start(self):
print("Yowsup Cli client\n==================\nType /help for available commands\n")
Expand Down
44 changes: 11 additions & 33 deletions yowsup/demos/contacts/stack.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
from yowsup.stacks import YowStack
from .layer import SyncLayer

from yowsup.stacks import YowStackBuilder
from yowsup.layers.auth import AuthError
from yowsup.layers import YowLayerEvent
from yowsup.layers.auth import YowCryptLayer, YowAuthenticationProtocolLayer, AuthError
from yowsup.layers.coder import YowCoderLayer
from yowsup.layers.network import YowNetworkLayer
from yowsup.layers.stanzaregulator import YowStanzaRegulator
from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer
from yowsup.layers.protocol_acks import YowAckProtocolLayer
from yowsup.layers.logger import YowLoggerLayer
from yowsup.layers.protocol_contacts import YowContactsIqProtocolLayer
from yowsup.layers import YowParallelLayer
from yowsup.layers.auth import YowAuthenticationProtocolLayer
from yowsup.layers.network import YowNetworkLayer

class YowsupSyncStack(object):
def __init__(self, credentials, contacts, encryptionEnabled = False):
Expand All @@ -19,30 +14,13 @@ def __init__(self, credentials, contacts, encryptionEnabled = False):
:param encryptionEnabled:
:return:
"""
if encryptionEnabled:
from yowsup.layers.axolotl import YowAxolotlLayer
layers = (
SyncLayer,
YowParallelLayer([YowAuthenticationProtocolLayer, YowContactsIqProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer]),
YowAxolotlLayer,
YowLoggerLayer,
YowCoderLayer,
YowCryptLayer,
YowStanzaRegulator,
YowNetworkLayer
)
else:
layers = (
SyncLayer,
YowParallelLayer([YowAuthenticationProtocolLayer, YowContactsIqProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer]),
YowLoggerLayer,
YowCoderLayer,
YowCryptLayer,
YowStanzaRegulator,
YowNetworkLayer
)
stackBuilder = YowStackBuilder()

self.stack = stackBuilder \
.pushDefaultLayers(encryptionEnabled) \
.push(SyncLayer) \
.build()

self.stack = YowStack(layers)
self.stack.setProp(SyncLayer.PROP_CONTACTS, contacts)
self.stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True)
self.stack.setCredentials(credentials)
Expand Down
21 changes: 17 additions & 4 deletions yowsup/env/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

logger = logging.getLogger(__name__)

DEFAULT = "s40"

class YowsupEnvType(abc.ABCMeta):
def __init__(cls, name, bases, dct):
if name != "YowsupEnv":
Expand All @@ -15,7 +17,7 @@ class YowsupEnv(with_metaclass(YowsupEnvType, object)):
__ENVS = {}
__CURR = None

_USERAGENT_STRING = "WhatsApp/{WHATSAPP_VERSION} {OS_NAME}/{OS_VERSION} Device/{DEVICE_NAME}"
_USERAGENT_STRING = "WhatsApp/{WHATSAPP_VERSION} {OS_NAME}/{OS_VERSION} Device/{MANUFACTURER}-{DEVICE_NAME}"

@classmethod
def registerEnv(cls, envCls):
Expand Down Expand Up @@ -44,9 +46,12 @@ def getRegisteredEnvs(cls):
@classmethod
def getCurrent(cls):
if cls.__CURR is None:
newEnvName = cls.getRegisteredEnvs()[0]
logger.debug("Env not set, setting it to %s" % newEnvName )
cls.setEnv(newEnvName)
env = DEFAULT
envs = cls.getRegisteredEnvs()
if env not in envs:
env = envs[0]
logger.debug("Env not set, setting it to %s" % env)
cls.setEnv(env)
return cls.__CURR

@abc.abstractmethod
Expand All @@ -69,10 +74,17 @@ def getOSName(self):
def getDeviceName(self):
pass

@abc.abstractmethod
def getManufacturer(self):
pass

@abc.abstractmethod
def isAxolotlEnabled(self):
pass

def getBuildVersion(self):
return ""

def getResource(self):
return self.getOSName() + "-" + self.getVersion()

Expand All @@ -81,5 +93,6 @@ def getUserAgent(self):
WHATSAPP_VERSION = self.getVersion(),
OS_NAME = self.getOSName(),
OS_VERSION = self.getOSVersion(),
MANUFACTURER = self.getManufacturer(),
DEVICE_NAME = self.getDeviceName()
)
10 changes: 9 additions & 1 deletion yowsup/env/env_android.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ class AndroidYowsupEnv(YowsupEnv):
_VERSION = "2.12.556"
_OS_NAME = "Android"
_OS_VERSION = "4.3"
_DEVICE_NAME = "GalaxyS3"
_DEVICE_NAME = "armani"
_MANUFACTURER = "Xiaomi"
_BUILD_VERSION = "JLS36C"
_AXOLOTL = True

def getVersion(self):
Expand All @@ -38,6 +40,12 @@ def getOSVersion(self):
def getDeviceName(self):
return self.__class__._DEVICE_NAME

def getBuildVersion(self):
return self.__class__._BUILD_VERSION

def getManufacturer(self):
return self.__class__._MANUFACTURER

def isAxolotlEnabled(self):
return self.__class__._AXOLOTL

Expand Down
11 changes: 7 additions & 4 deletions yowsup/env/env_s40.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from .env import YowsupEnv
import base64
import hashlib
class S40YowsupEnv(YowsupEnv):
_VERSION = "2.13.39"
_VERSION = "2.16.7"
_OS_NAME= "S40"
_OS_VERSION = "14.26"
_DEVICE_NAME = "302"
_MANUFACTURER = "Nokia"
_TOKEN_STRING = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1456529096701{phone}"
_TOKEN_STRING = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1462212402694{phone}"
_AXOLOTL = True

def getVersion(self):
Expand All @@ -22,6 +21,9 @@ def getOSVersion(self):
def getDeviceName(self):
return self.__class__._DEVICE_NAME

def getManufacturer(self):
return self.__class__._MANUFACTURER

def isAxolotlEnabled(self):
return self.__class__._AXOLOTL

Expand All @@ -33,5 +35,6 @@ def getUserAgent(self):
WHATSAPP_VERSION = self.getVersion(),
OS_NAME = self.getOSName() + "Version",
OS_VERSION = self.getOSVersion(),
DEVICE_NAME = self.getDeviceName()
DEVICE_NAME = self.getDeviceName(),
MANUFACTURER = self.getManufacturer()
)
1 change: 1 addition & 0 deletions yowsup/layers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self):
self.setLayers(None, None)
self.interface = None
self.event_callbacks = {}
self.__stack = None
members = inspect.getmembers(self, predicate=inspect.ismethod)
for m in members:
if hasattr(m[1], "event_callback"):
Expand Down
27 changes: 18 additions & 9 deletions yowsup/layers/auth/layer_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
from .autherror import AuthError
from .protocolentities import *
from yowsup.common.tools import StorageTools
from yowsup.env import YowsupEnv
from .layer_interface_authentication import YowAuthenticationProtocolLayerInterface
from .protocolentities import StreamErrorProtocolEntity
import base64

class YowAuthenticationProtocolLayer(YowProtocolLayer):
EVENT_LOGIN = "org.openwhatsapp.yowsup.event.auth.login"
EVENT_AUTHED = "org.openwhatsapp.yowsup.event.auth.authed"
Expand Down Expand Up @@ -48,7 +51,7 @@ def getUsername(self, full = False):
else:
prop = self.getProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS)
return prop[0] if prop else None

@EventCallback(YowNetworkLayer.EVENT_STATE_CONNECTED)
def onConnected(self, yowLayerEvent):
self.login()
Expand Down Expand Up @@ -82,17 +85,17 @@ def handleChallenge(self, node):
self._sendResponse(nodeEntity.getNonce())

def handleStreamError(self, node):
if node.getChild("text"):
nodeEntity = StreamErrorConflictProtocolEntity.fromProtocolTreeNode(node)
elif node.getChild("ack"):
nodeEntity = StreamErrorAckProtocolEntity.fromProtocolTreeNode(node)
else:
nodeEntity = StreamErrorProtocolEntity.fromProtocolTreeNode(node)
errorType = nodeEntity.getErrorType()

if not errorType:
raise AuthError("Unhandled stream:error node:\n%s" % node)

self.toUpper(nodeEntity)

##senders
def _sendFeatures(self):
self.entityToLower(StreamFeaturesProtocolEntity(["readreceipts", "groups_v2", "privacy", "presence"]))
self.entityToLower(StreamFeaturesProtocolEntity([]))

def _sendAuth(self):
passive = self.getProp(self.__class__.PROP_PASSIVE, False)
Expand Down Expand Up @@ -121,6 +124,7 @@ def _sendResponse(self,nonce):

def generateAuthBlob(self, nonce):
keys = KeyStream.generateKeys(self.credentials[1], nonce)
currentEnv = YowsupEnv.getCurrent()

inputKey = KeyStream(keys[2], keys[3])
outputKey = KeyStream(keys[0], keys[1])
Expand All @@ -138,11 +142,16 @@ def generateAuthBlob(self, nonce):
nums.extend(nonce)

utcNow = str(int(TimeTools.utcTimestamp()))

time_bytes = list(map(ord, utcNow))

nums.extend(time_bytes)

strCat = "\x00\x00\x00\x00\x00\x00\x00\x00"
strCat += currentEnv.getOSVersion() + "\x00"
strCat += currentEnv.getManufacturer() + "\x00"
strCat += currentEnv.getDeviceName() + "\x00"
strCat += currentEnv.getBuildVersion()
nums.extend(list(map(ord, strCat)))

encoded = outputKey.encodeMessage(nums, 0, 4, len(nums) - 4)
authBlob = "".join(map(chr, encoded))

Expand Down
3 changes: 1 addition & 2 deletions yowsup/layers/auth/protocolentities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@
from .stream_features import StreamFeaturesProtocolEntity
from .success import SuccessProtocolEntity
from .failure import FailureProtocolEntity
from .stream_error_conflict import StreamErrorConflictProtocolEntity
from .stream_error_ack import StreamErrorAckProtocolEntity
from .stream_error import StreamErrorProtocolEntity
Loading

0 comments on commit f510d44

Please sign in to comment.