def __init__(self, config_class): super(ConfigSerialize, self).__init__( transforms=( ConfigDictTransform(config_class), FilterTransform( transform_filter=lambda key, val: val is not None, reverse_filter=lambda key, val: key != "version" ), MapTransform(transform_map=lambda key, val: (key[1:], val)), PropsTransform( transform_map={ "server_static_public": lambda key, val: (key, base64.b64encode(val.data).decode()), "client_static_keypair": lambda key, val: (key, base64.b64encode(val.private.data + val.public.data).decode()), "id": lambda key, val: (key, base64.b64encode(val).decode()), "expid": lambda key, val: (key, base64.b64encode(val).decode()), "edge_routing_info": lambda key, val: (key, base64.b64encode(val).decode()) }, reverse_map={ "server_static_public": lambda key, val: (key, PublicKey(base64.b64decode(val))), "client_static_keypair": lambda key, val: (key, KeyPair.from_bytes(base64.b64decode(val))), "id": lambda key, val: (key, base64.b64decode(val)), "expid": lambda key, val: (key, base64.b64decode(val)), "edge_routing_info": lambda key, val: (key, base64.b64decode(val)) } ), MetaPropsTransform(meta_props=("version", )), ) )
def run(wttQueue, ttwQueue, config): logger.info("Starting Whatsapp Self-Bot") keypair = KeyPair.from_bytes( base64.b64decode(config["client_static_keypair"])) credentials = (config["phone"], keypair) layers = ( WhatsappLayer(wttQueue, ttwQueue), YowParallelLayer([ YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowIqProtocolLayer, YowGroupsProtocolLayer, YowMediaProtocolLayer ]), AxolotlControlLayer, YowParallelLayer((AxolotlSendLayer, AxolotlReceivelayer)), ) + YOWSUP_CORE_LAYERS stack = YowStack(layers) stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, credentials) # setting credentials stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0]) # whatsapp server address # stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN) # stack.setProp(YowCoderLayer.PROP_RESOURCE, YowsupEnv.getCurrent().getResource()) #info about us as WhatsApp client stack.broadcastEvent(YowLayerEvent( YowNetworkLayer.EVENT_STATE_CONNECT)) # sending the connect signal stack.loop()
class HandshakesTest(unittest.TestCase): USERNAME = 123456789 KEYPAIR = KeyPair.generate() PHONE_ID = uuid.uuid4().__str__() CONFIG = ClientConfig(username=USERNAME, passive=True, useragent=VBoxUserAgentConfig( app_version="2.19.51", phone_id=PHONE_ID, mcc="000", mnc="000", ), pushname="consonance", short_connect=True) ENDPOINT = ("e1.whatsapp.net", 443) HEADER = b"WA\x02\x01" def test_xx_handshake(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(self.ENDPOINT) # send WA header indicating protocol version s.send(self.HEADER) # use WASegmentedStream for sending/receiving in frames stream = WASegmentedStream(SocketArbitraryStream(s)) # initialize WANoiseProtocol 2.1 wa_noiseprotocol = WANoiseProtocol(2, 1) # start the protocol, this should a XX handshake since # we are not passing the remote static public key self.assertTrue( wa_noiseprotocol.start(stream, self.CONFIG, self.KEYPAIR)) # we are now in transport phase, first incoming data # will indicate whether we are authenticated first_transport_data = wa_noiseprotocol.receive() # fourth byte is status, 172 is success, 52 is failure self.assertEqual(52, first_transport_data[3])
class HandshakesTest(unittest.TestCase): KEYPAIR = KeyPair.from_bytes( base64.b64decode( b"YJa8Vd9pG0KV2tDYi5V+DMOtSvCEFzRGCzOlGZkvBHzJvBE5C3oC2Fruniw0GBGo7HHgR4TjvjI3C9AihStsVg==" )) PHONE_ID = uuid.uuid4().__str__() CONFIG = ClientConfig(username=1, passive=True, useragent=VBoxUserAgentConfig( app_version="2.19.51", phone_id=PHONE_ID, mcc="000", mnc="000", ), pushname="consonance", short_connect=True) def test_xx_handshake_offline(self): stream = DummySegmentedStream([ base64.b64decode( b"GvoBCiCiMwovEL8pYkUdcxCz6w5lvzvyxgAgHiNm4LnOwO8KQxIwt+dvmTcTMcE12jCC" b"rbnLcFY+H2/QuKr4/h4BCHy0rDS9rKp63yqRfFX5vEPY0/UGGqMBCfYtpYzsdsU3cN0Bq4ui5Dm0MY/+Yur2cCFb" b"tLRgBa858hWFuCIuWKrkE89GrF0uo+wJsolq4miiqMOdXJfuZ2YBZ4paFS2mWjVmQSINRo8J3LzXncUDMeQBO/KkC" b"ARw5BTcVkj2gwI6FG+yB/qI8BUJIxxswJc6q+H+HWkNro+Xl6urn5aOwK7bgBSPNctncZGY72NlJByEQCB6Bra7U" b"ykzQA==") ]) ephemeral = KeyPair.from_bytes( base64.b64decode( b"qLt+l8Jh9mUF/QciIRjd7Z0qKyhN//46Xawk5jdL4WF4tFaszfGgyodH3ErvqU5lV4GnOccdy9zj39GU6AAPVQ==" )) # initialize WANoiseProtocol 2.1 wa_handshake = WAHandshake(2, 1) # this should do a XX handshake since we are not passing the remote static public key wa_handshake.perform(self.CONFIG, stream, self.KEYPAIR, e=ephemeral)
def on_auth(self, event): logger.debug("Received auth event") credentials = event.getArg("credentials") self._username, local_static = int(credentials[0]), credentials[1] config = self._config_manager.load( self._username) # type: yowsup.config.v1.config.Config # event's keypair will override config's keypair local_static = local_static or config.client_static_keypair if type(local_static) is bytes: local_static = KeyPair.from_bytes(local_static) assert type(local_static) is KeyPair passive = event.getArg('passive') self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) if config.edge_routing_info: self.toLower(self.EDGE_HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) self.toLower(config.edge_routing_info) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) self.toLower(self.HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) remote_static = config.server_static_public self._rs = remote_static yowsupenv = YowsupEnv.getCurrent() client_config = ClientConfig( username=self._username, passive=passive, useragent=UserAgentConfig(platform=0, app_version="2.19.51", mcc=config.mcc, mnc=config.mnc, os_version=yowsupenv.getOSVersion(), manufacturer=yowsupenv.getManufacturer(), device=yowsupenv.getDeviceName(), os_build_number=yowsupenv.getOSVersion(), phone_id=config.fdid, locale_lang="en", locale_country="US"), pushname=config.pushname or self.DEFAULT_PUSHNAME, short_connect=True) if not self._in_handshake(): logger.debug("Performing handshake [username= %d, passive=%s]" % (self._username, passive)) self._handshake_worker = WANoiseProtocolHandshakeWorker( self._wa_noiseprotocol, self._stream, client_config, local_static, remote_static, ) logger.debug("Starting handshake worker") self._stream.set_events_callback(self._handle_stream_event) self._handshake_worker.start()
def on_auth(self, event): logger.debug("Received auth event") credentials = event.getArg("credentials") self._username, local_static = int(credentials[0]), credentials[1] config = self._config_manager.load(self._username) # type: yowsup.config.v1.config.Config # event's keypair will override config's keypair local_static = local_static or config.client_static_keypair if type(local_static) is bytes: local_static = KeyPair.from_bytes(local_static) assert type(local_static) is KeyPair passive = event.getArg('passive') self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) if config.edge_routing_info: self.toLower(self.EDGE_HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) self.toLower(config.edge_routing_info) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) self.toLower(self.HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) remote_static = config.server_static_public self._rs = remote_static yowsupenv = YowsupEnv.getCurrent() client_config = ClientConfig( username=self._username, passive=passive, useragent=UserAgentConfig( platform=0, app_version=yowsupenv.getVersion(), mcc=config.mcc or "000", mnc=config.mnc or "000", os_version=yowsupenv.getOSVersion(), manufacturer=yowsupenv.getManufacturer(), device=yowsupenv.getDeviceName(), os_build_number=yowsupenv.getOSVersion(), phone_id=config.fdid or "", locale_lang="en", locale_country="US" ), pushname=config.pushname or self.DEFAULT_PUSHNAME, short_connect=True ) if not self._in_handshake(): logger.debug("Performing handshake [username= %d, passive=%s]" % (self._username, passive) ) self._handshake_worker = WANoiseProtocolHandshakeWorker( self._wa_noiseprotocol, self._stream, client_config, local_static, remote_static, ) logger.debug("Starting handshake worker") self._stream.set_events_callback(self._handle_stream_event) self._handshake_worker.start()
def test_xx_handshake_offline(self): stream = DummySegmentedStream([ base64.b64decode( b"GvoBCiCiMwovEL8pYkUdcxCz6w5lvzvyxgAgHiNm4LnOwO8KQxIwt+dvmTcTMcE12jCC" b"rbnLcFY+H2/QuKr4/h4BCHy0rDS9rKp63yqRfFX5vEPY0/UGGqMBCfYtpYzsdsU3cN0Bq4ui5Dm0MY/+Yur2cCFb" b"tLRgBa858hWFuCIuWKrkE89GrF0uo+wJsolq4miiqMOdXJfuZ2YBZ4paFS2mWjVmQSINRo8J3LzXncUDMeQBO/KkC" b"ARw5BTcVkj2gwI6FG+yB/qI8BUJIxxswJc6q+H+HWkNro+Xl6urn5aOwK7bgBSPNctncZGY72NlJByEQCB6Bra7U" b"ykzQA==") ]) ephemeral = KeyPair.from_bytes( base64.b64decode( b"qLt+l8Jh9mUF/QciIRjd7Z0qKyhN//46Xawk5jdL4WF4tFaszfGgyodH3ErvqU5lV4GnOccdy9zj39GU6AAPVQ==" )) # initialize WANoiseProtocol 2.1 wa_handshake = WAHandshake(2, 1) # this should do a XX handshake since we are not passing the remote static public key wa_handshake.perform(self.CONFIG, stream, self.KEYPAIR, e=ephemeral)
def __init__(self, config_class): super(ConfigSerialize, self).__init__(transforms=( ConfigDictTransform(config_class), FilterTransform(transform_filter=lambda key, val: val is not None, reverse_filter=lambda key, val: key != "version"), MapTransform(transform_map=lambda key, val: (key[1:], val)), PropsTransform(transform_map={ "server_static_public": lambda key, val: (key, base64.b64encode(val.data).decode()), "client_static_keypair": lambda key, val: (key, base64.b64encode(val.private.data + val.public.data). decode()), "id": lambda key, val: (key, base64.b64encode(val).decode()), "expid": lambda key, val: (key, base64.b64encode(val).decode()), "edge_routing_info": lambda key, val: (key, base64.b64encode(val).decode()) }, reverse_map={ "server_static_public": lambda key, val: (key, PublicKey(base64.b64decode(val))), "client_static_keypair": lambda key, val: (key, KeyPair.from_bytes(base64.b64decode(val)) ), "id": lambda key, val: (key, base64.b64decode(val)), "expid": lambda key, val: (key, base64.b64decode(val)), "edge_routing_info": lambda key, val: (key, base64.b64decode(val)) }), MetaPropsTransform(meta_props=("version", )), ))
import consonance import uuid import dissononce import socket import logging import sys import base64 consonance.logger.setLevel(logging.DEBUG) dissononce.logger.setLevel(logging.DEBUG) # username is phone number USERNAME = 123456789 # on Android fetch client_static_keypair from /data/data/com.whatsapp/shared_prefs/keystore.xml KEYPAIR = KeyPair.from_bytes( base64.b64decode( b"YJa8Vd9pG0KV2tDYi5V+DMOtSvCEFzRGCzOlGZkvBHzJvBE5C3oC2Fruniw0GBGo7HHgR4TjvjI3C9AihStsVg==" )) # same phone_id/fdid used at registration. # on Android it's phoneid_id under /data/data/com.whatsapp/shared_prefs/com.whatsapp_preferences.xml PHONE_ID = uuid.uuid4().__str__() # create full configuration which will translate later into a protobuf payload CONFIG = ClientConfig(username=USERNAME, passive=True, useragent=SamsungS9PUserAgentConfig( app_version="2.21.21.18", phone_id=PHONE_ID), pushname="consonance", short_connect=True) PROTOCOL_VERSION = (4, 0) ENDPOINT = ("e1.whatsapp.net", 443) HEADER = b"WA" + bytes(PROTOCOL_VERSION)
def on_auth(self, event): logger.debug("Received auth event") self._profile = self.getProp("profile") config = self._profile.config # type: yowsup.config.v1.config.Config # event's keypair will override config's keypair local_static = config.client_static_keypair username = int(self._profile.username) if local_static is None: logger.error( "client_static_keypair is not defined in specified config, disconnecting" ) self.broadcastEvent( YowLayerEvent( YowNetworkLayer.EVENT_STATE_DISCONNECT, reason= "client_static_keypair is not defined in specified config") ) else: if type(local_static) is bytes: local_static = KeyPair.from_bytes(local_static) assert type(local_static) is KeyPair, type(local_static) passive = event.getArg('passive') self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) if config.edge_routing_info: self.toLower(self.EDGE_HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) self.toLower(config.edge_routing_info) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, False) self.toLower(self.HEADER) self.setProp(YowNoiseSegmentsLayer.PROP_ENABLED, True) remote_static = config.server_static_public self._rs = remote_static yowsupenv = YowsupEnv.getCurrent() client_config = ClientConfig( username=username, passive=passive, useragent=UserAgentConfig( platform=0, app_version=yowsupenv.getVersion(), mcc=config.mcc or "000", mnc=config.mnc or "000", os_version=yowsupenv.getOSVersion(), manufacturer=yowsupenv.getManufacturer(), device=yowsupenv.getDeviceName(), os_build_number=yowsupenv.getOSVersion(), phone_id=config.fdid or "", locale_lang="en", locale_country="US"), pushname=config.pushname or self.DEFAULT_PUSHNAME, short_connect=True) if not self._in_handshake(): logger.debug( "Performing handshake [username= %d, passive=%s]" % (username, passive)) self._handshake_worker = WANoiseProtocolHandshakeWorker( self._wa_noiseprotocol, self._stream, client_config, local_static, remote_static, self.on_handshake_finished) logger.debug("Starting handshake worker") self._stream.set_events_callback(self._handle_stream_event) self._handshake_worker.start()
def generateKeyPair(cls): """ :return: :rtype: KeyPair """ return KeyPair.generate()
from yowsup.layers.network import YowNetworkLayer from consonance.structs.keypair import KeyPair import base64 from app.layer import MacLayer import threading from flask import Flask, request, g from app.utils import helper import json # Uncomment to log #logging.basicConfig(level=logging.DEBUG) # Config credentials = config.credentials['phone'], KeyPair.from_bytes(base64.b64decode(config.credentials['password'])) encryption = True class WS(object): def __init__(self): self.app = Flask(__name__) @self.app.route("/send", methods=['POST']) def send(): body = request.json MacLayer.send_message(body['text'].replace("\n", "\n"), body['conversation']) return helper.json_response(status=201) thread = threading.Thread(target=self.run, args=()) thread.daemon = True thread.start()
from yowsup.stacks import YowStackBuilder from layer import EchoLayer from yowsup.layers import YowLayerEvent from yowsup.layers.network import YowNetworkLayer from yowsup.env import YowsupEnv from yowsup.layers.axolotl.props import PROP_IDENTITY_AUTOTRUST from consonance.structs.keypair import KeyPair import base64 import sys import config credentials = (config.credentials["PHONE"], KeyPair.from_bytes(base64.b64decode(config.credentials["CLIENT_STATIC_KEYPAIR"]))) if __name__== "__main__": stackBuilder = YowStackBuilder() try: stack = stackBuilder\ .pushDefaultLayers()\ .push(EchoLayer)\ .build() stack.setCredentials(credentials) stack.setProp(PROP_IDENTITY_AUTOTRUST, True) stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT)) # sending the connect signal stack.loop() except KeyboardInterrupt: sys.exit(0) except: