Beispiel #1
0
    def set_dc(self, dc_id, server_address, port):
        super().set_dc(dc_id, server_address, port)
        self._update_sessions()

        auth_key = bytes()

        if not self._dc_id:
            self._auth_key = AuthKey(data=auth_key)
            return

        key_pattern = "{}:auth".format(self.sess_prefix)
        s = self.redis_connection.hgetall(key_pattern)
        if s:
            auth_key = s.get(b'auth_key') or auth_key
            self._auth_key = AuthKey(s.get(auth_key))
Beispiel #2
0
    def set_dc(self, dc_id, server_address, port):
        # print('django session set_dc')
        # print('django session set_dc dc_id ' + str(dc_id))
        # print('django session set_dc server_address ' + str(server_address))
        # print('django session set_dc port ' + str(port))
        super().set_dc(dc_id, server_address, port)
        self._update_session_table()

        # Fetch the auth_key corresponding to this data center
        # row = self._execute('select auth_key from sessions')
        # if row and row[0]:
        #     self._auth_key = AuthKey(data=row[0])
        # else:
        #     self._auth_key = None
        auth_keys = TelethonSession.objects.filter(
            client_session_name=self.client_session_name)
        # print(auth_keys)
        if auth_keys and auth_keys[0]:
            # print(auth_keys[0].auth_key)
            # print(type(auth_keys[0].auth_key))
            akey = auth_keys[0].auth_key
            if isinstance(akey, memoryview):
                akey = akey.tobytes()
            self._auth_key = AuthKey(data=akey)
        else:
            self._auth_key = None
Beispiel #3
0
    def __init__(self, client_session_name: str = 'default'):
        super().__init__()
        # print('django session init')
        self.save_entities = True
        self.client_session_name = client_session_name

        # db_sessions = TelethonSession.objects.all()
        # if db_sessions.count() > 0:
        #     db_session = db_sessions[0]
        db_session = TelethonSession.objects.filter(
            client_session_name=self.client_session_name).first()
        if db_session is not None:
            self._dc_id = db_session.dc_id
            self._server_address = db_session.server_address
            self._port = db_session.port
            self._takeout_id = db_session.takeout_id

            akey = db_session.auth_key
            if isinstance(akey, memoryview):
                akey = akey.tobytes()
            self._auth_key = AuthKey(data=akey)
            # print('django session init finish 1')
        else:
            self._update_session_table()
            self.save()
    def __init__(self, database, **kwargs):
        super().__init__()
        self.save_entities = True
        self.database = database

        connect(database, alias=database, **kwargs)

        # Do a version check
        with switch_db(Version, database) as _Version:
            version_count = _Version.objects.count()
            if version_count < 1:
                # Add the first version record
                _Version(version=CURRENT_VERSION).save()
            else:
                # Check if the version is below the current version
                lt_versions = _Version.objects(version__lt=CURRENT_VERSION)
                if len(lt_versions) > 0:
                    version = _Version.objects().order_by(
                        'version').first().version
                    self._update_database(old=version)
                    # Delete old versions
                    for version in lt_versions:
                        version.delete()

        # See if we have any previous sessions
        with switch_db(Session, database) as _Session:
            session_count = _Session.objects.count()
            print(session_count)
            if session_count > 0:
                session = _Session.objects.first()
                self._dc_id = session.dc_id
                self._server_address = session.server_address
                self._port = session.port
                self._takeout_id = session.takeout_id
                self._auth_key = AuthKey(data=session.auth_key)
Beispiel #5
0
 def _load_session(self) -> None:
     sessions = self._db_query(self.Session).all()
     session = sessions[0] if sessions else None
     if session:
         self._dc_id = session.dc_id
         self._server_address = session.server_address
         self._port = session.port
         self._auth_key = AuthKey(data=session.auth_key)
 def _load_session(self):
     session = models.Session.objects.filter(
         session_id=self.session_id).first()
     if session:
         self._dc_id = session.dc_id
         self._server_address = session.server_address
         self._port = session.port
         self._auth_key = AuthKey(session.auth_key.tobytes())
Beispiel #7
0
 def _get_auth_key(self) -> Optional[AuthKey]:
     t = self.Session.__table__
     rows = self.engine.execute(
         select([t.c.auth_key]).where(t.c.session_id == self.session_id))
     try:
         ak = next(rows)[0]
     except (StopIteration, IndexError):
         ak = None
     return AuthKey(data=ak) if ak else None
    def set_dc(self, dc_id, server_address, port):
        super().set_dc(dc_id, server_address, port)
        self._update_session_table()

        # Fetch the auth key corresponding to this data center
        row = Session.objects.first()
        if row and row.auth_key:
            self._auth_key = AuthKey(data=row.auth_key)
        else:
            self._auth_key = None
    def set_dc(self, dc_id, server_address, port):
        super().set_dc(dc_id, server_address, port)
        self._update_session_table()

        session = models.Session.objects.filter(
            session_id=self.session_id).first()
        if session and session.auth_key:
            self._auth_key = AuthKey(data=session.auth_key.tobytes())
        else:
            self._auth_key = None
    def set_dc(self, dc_id, server_address, port):
        super().set_dc(dc_id, server_address, port)
        self._update_session_table()

        sessions = self._db_query(self.Session).all()
        session = sessions[0] if sessions else None
        if session and session.auth_key:
            self._auth_key = AuthKey(data=session.auth_key)
        else:
            self._auth_key = None
Beispiel #11
0
 def _load_session(self) -> None:
     t = self.Session.__table__
     rows = self.engine.execute(
         select([t.c.dc_id, t.c.server_address, t.c.port,
                 t.c.auth_key]).where(t.c.session_id == self.session_id))
     try:
         self._dc_id, self._server_address, self._port, auth_key = next(
             rows)
         self._auth_key = AuthKey(data=auth_key)
     except StopIteration:
         pass
    def feed_session(self):
        try:
            s = self._get_sessions()
            if len(s) == 0:
                self._auth_key = AuthKey(data=bytes())
                return

            s = self.redis_connection.get(s[-1])
            if not s:
                # No sessions
                self._auth_key = AuthKey(data=bytes())
                return

            s = self._unpack(s)
            self._dc_id = s["dc_id"]
            self._server_address = s["server_address"]
            self._port = s["port"]
            auth_key = base64.standard_b64decode(s["auth_key"])
            self._auth_key = AuthKey(data=auth_key)
        except Exception as ex:
            __log__.exception(ex.args)
    def set_dc(self, dc_id, server_address, port):
        """
        Sets the information of the data center address and port that
        the library should connect to, as well as the data center ID,
        which is currently unused.
        """
        super().set_dc(dc_id, server_address, port)
        self._update_sessions()

        auth_key = bytes()

        if not self._dc_id:
            self._auth_key = AuthKey(data=auth_key)
            return

        key = "{}:sessions:{}".format(self.sess_prefix, self._dc_id)
        s = self.redis_connection.get(key)
        if s:
            s = self._unpack(s)
            auth_key = base64.standard_b64decode(s["auth_key"])
        self._auth_key = AuthKey(data=auth_key)
Beispiel #14
0
    def __init__(self, string=None):
        super().__init__()
        if string:
            if string[0] != CURRENT_VERSION:
                raise ValueError('Not a valid string')

            string = string[1:]
            ip_len = 4 if len(string) == 352 else 16
            self._dc_id, ip, self._port, key = struct.unpack(
                _STRUCT_PREFORMAT.format(ip_len), StringSession.decode(string))

            self._server_address = ipaddress.ip_address(ip).compressed
            if any(key):
                self._auth_key = AuthKey(key)
    def set_dc(self, dc_id, server_address, port):
        super().set_dc(dc_id, server_address, port)
        self._update_session_table()

        session_container = self.get_session_container()
        query = 'SELECT * FROM c'
        
        for item in session_container.query_items(query, enable_cross_partition_query=True):
            if item and item['auth_key']:
                self._auth_key = AuthKey(
                    data=self.intlist_to_byte(item['auth_key']))
            else:
                self._auth_key = None
            break
Beispiel #16
0
    def __init__(self, string=None):
        super().__init__()
        if string:
            if string[0] != CURRENT_VERSION:
                raise ValueError('Not a valid string')

            string = string[1:]
            ip_len = 4 if len(string) == 352 else 16
            self._dc_id, ip, self._port, key = struct.unpack(
                '>B{}sH256s'.format(ip_len), base64.urlsafe_b64decode(string))

            self._server_address = ipaddress.ip_address(ip).compressed
            if any(key):
                self._auth_key = AuthKey(key)
Beispiel #17
0
    def feed_session(self):
        try:
            s = self._get_sessions()
            if len(s) == 0:
                return

            s = self.redis_connection.hgetall(s[-1])
            if not s:
                return

            self._dc_id = int(s.get(b'dc_id').decode())
            self._server_address = s.get(b'server_address').decode()
            self._port = int(s.get(b'port').decode())
            self._takeout_id = (s.get(b'takeout_id').decode() if s.get(
                b'takeout_id', False) else None)

            if s.get(b'auth_key', False):
                self._auth_key = AuthKey(s.get(b'auth_key'))

        except Exception as ex:
            LOGGER.exception(ex.args)
 def __init__(self, session_name, endpoint, key, database_name, **kwargs):
     super().__init__()
     self.save_entities = True
     self.endpoint = endpoint
     self.key = key
     self.database_name = database_name
     self.session_name = session_name
     
     # Get Cosmos DB client
     self.cosmos_client = CosmosClient(self.endpoint, self.key, **kwargs)
     self.cosmosdb = self.cosmos_client.create_database_if_not_exists(self.database_name)
     
     # Look for existing session
     session_container = self.get_session_container()
     query = 'SELECT * FROM c'
     for item in session_container.query_items(query, enable_cross_partition_query=True):
         self._dc_id = item['dc_id']
         self._server_address = item['server_address']
         self._port = item['port']
         self._takeout_id = item['takeout_id']
         self._auth_key = AuthKey(
             data=self.intlist_to_byte(item['auth_key']))
         break
    def __init__(self,
                 auth_key,
                 loop,
                 *,
                 loggers,
                 retries=5,
                 delay=1,
                 auto_reconnect=True,
                 connect_timeout=None,
                 auth_key_callback=None,
                 update_callback=None,
                 auto_reconnect_callback=None):
        self._connection = None
        self._loop = loop
        self._loggers = loggers
        self._log = loggers[__name__]
        self._retries = retries
        self._delay = delay
        self._auto_reconnect = auto_reconnect
        self._connect_timeout = connect_timeout
        self._auth_key_callback = auth_key_callback
        self._update_callback = update_callback
        self._auto_reconnect_callback = auto_reconnect_callback
        self._connect_lock = asyncio.Lock(loop=loop)

        # Whether the user has explicitly connected or disconnected.
        #
        # If a disconnection happens for any other reason and it
        # was *not* user action then the pending messages won't
        # be cleared but on explicit user disconnection all the
        # pending futures should be cancelled.
        self._user_connected = False
        self._reconnecting = False
        self._disconnected = self._loop.create_future()
        self._disconnected.set_result(None)

        # We need to join the loops upon disconnection
        self._send_loop_handle = None
        self._recv_loop_handle = None

        # Preserving the references of the AuthKey and state is important
        self.auth_key = auth_key or AuthKey(None)
        self._state = MTProtoState(self.auth_key, loggers=self._loggers)

        # Outgoing messages are put in a queue and sent in a batch.
        # Note that here we're also storing their ``_RequestState``.
        self._send_queue = MessagePacker(self._state,
                                         self._loop,
                                         loggers=self._loggers)

        # Sent states are remembered until a response is received.
        self._pending_state = {}

        # Responses must be acknowledged, and we can also batch these.
        self._pending_ack = set()

        # Similar to pending_messages but only for the last acknowledges.
        # These can't go in pending_messages because no acknowledge for them
        # is received, but we may still need to resend their state on bad salts.
        self._last_acks = collections.deque(maxlen=10)

        # Jump table from response ID to method that handles it
        self._handlers = {
            RpcResult.CONSTRUCTOR_ID: self._handle_rpc_result,
            MessageContainer.CONSTRUCTOR_ID: self._handle_container,
            GzipPacked.CONSTRUCTOR_ID: self._handle_gzip_packed,
            Pong.CONSTRUCTOR_ID: self._handle_pong,
            BadServerSalt.CONSTRUCTOR_ID: self._handle_bad_server_salt,
            BadMsgNotification.CONSTRUCTOR_ID: self._handle_bad_notification,
            MsgDetailedInfo.CONSTRUCTOR_ID: self._handle_detailed_info,
            MsgNewDetailedInfo.CONSTRUCTOR_ID: self._handle_new_detailed_info,
            NewSessionCreated.CONSTRUCTOR_ID: self._handle_new_session_created,
            MsgsAck.CONSTRUCTOR_ID: self._handle_ack,
            FutureSalts.CONSTRUCTOR_ID: self._handle_future_salts,
            MsgsStateReq.CONSTRUCTOR_ID: self._handle_state_forgotten,
            MsgResendReq.CONSTRUCTOR_ID: self._handle_state_forgotten,
            MsgsAllInfo.CONSTRUCTOR_ID: self._handle_msg_all,
        }
Beispiel #20
0
 def _get_auth_key(self) -> Optional[AuthKey]:
     sessions = self._db_query(self.Session).all()
     session = sessions[0] if sessions else None
     if session and session.auth_key:
         return AuthKey(data=session.auth_key)
     return None
Beispiel #21
0
def do_authentication(transport):
    """Executes the authentication process with the Telegram servers.
    If no error is rose, returns both the authorization key and the time offset"""
    sender = MtProtoPlainSender(transport)

    # Step 1 sending: PQ Request
    nonce = os.urandom(16)
    with BinaryWriter() as writer:
        writer.write_int(0x60469778, signed=False)  # Constructor number
        writer.write(nonce)
        sender.send(writer.get_bytes())

    # Step 1 response: PQ Request
    pq, pq_bytes, server_nonce, fingerprints = None, None, None, []
    with BinaryReader(sender.receive()) as reader:
        response_code = reader.read_int(signed=False)
        if response_code != 0x05162463:
            raise AssertionError('Invalid response code: {}'.format(
                hex(response_code)))

        nonce_from_server = reader.read(16)
        if nonce_from_server != nonce:
            raise AssertionError('Invalid nonce from server')

        server_nonce = reader.read(16)

        pq_bytes = reader.tgread_bytes()
        pq = get_int(pq_bytes)

        vector_id = reader.read_int()
        if vector_id != 0x1cb5c415:
            raise AssertionError('Invalid vector constructor ID: {}'.format(
                hex(response_code)))

        fingerprints = []
        fingerprint_count = reader.read_int()
        for _ in range(fingerprint_count):
            fingerprints.append(reader.read(8))

    # Step 2 sending: DH Exchange
    new_nonce = os.urandom(32)
    p, q = Factorizator.factorize(pq)
    with BinaryWriter() as pq_inner_data_writer:
        pq_inner_data_writer.write_int(
            0x83c95aec, signed=False)  # PQ Inner Data
        pq_inner_data_writer.tgwrite_bytes(get_byte_array(pq, signed=False))
        pq_inner_data_writer.tgwrite_bytes(
            get_byte_array(
                min(p, q), signed=False))
        pq_inner_data_writer.tgwrite_bytes(
            get_byte_array(
                max(p, q), signed=False))
        pq_inner_data_writer.write(nonce)
        pq_inner_data_writer.write(server_nonce)
        pq_inner_data_writer.write(new_nonce)

        cipher_text, target_fingerprint = None, None
        for fingerprint in fingerprints:
            cipher_text = RSA.encrypt(
                get_fingerprint_text(fingerprint),
                pq_inner_data_writer.get_bytes())

            if cipher_text is not None:
                target_fingerprint = fingerprint
                break

        if cipher_text is None:
            raise AssertionError(
                'Could not find a valid key for fingerprints: {}'
                .format(', '.join([get_fingerprint_text(f)
                                   for f in fingerprints])))

        with BinaryWriter() as req_dh_params_writer:
            req_dh_params_writer.write_int(
                0xd712e4be, signed=False)  # Req DH Params
            req_dh_params_writer.write(nonce)
            req_dh_params_writer.write(server_nonce)
            req_dh_params_writer.tgwrite_bytes(
                get_byte_array(
                    min(p, q), signed=False))
            req_dh_params_writer.tgwrite_bytes(
                get_byte_array(
                    max(p, q), signed=False))
            req_dh_params_writer.write(target_fingerprint)
            req_dh_params_writer.tgwrite_bytes(cipher_text)

            req_dh_params_bytes = req_dh_params_writer.get_bytes()
            sender.send(req_dh_params_bytes)

    # Step 2 response: DH Exchange
    encrypted_answer = None
    with BinaryReader(sender.receive()) as reader:
        response_code = reader.read_int(signed=False)

        if response_code == 0x79cb045d:
            raise AssertionError('Server DH params fail: TODO')

        if response_code != 0xd0e8075c:
            raise AssertionError('Invalid response code: {}'.format(
                hex(response_code)))

        nonce_from_server = reader.read(16)
        if nonce_from_server != nonce:
            raise NotImplementedError('Invalid nonce from server')

        server_nonce_from_server = reader.read(16)
        if server_nonce_from_server != server_nonce:
            raise NotImplementedError('Invalid server nonce from server')

        encrypted_answer = reader.tgread_bytes()

    # Step 3 sending: Complete DH Exchange
    key, iv = utils.generate_key_data_from_nonces(server_nonce, new_nonce)
    plain_text_answer = AES.decrypt_ige(encrypted_answer, key, iv)

    g, dh_prime, ga, time_offset = None, None, None, None
    with BinaryReader(plain_text_answer) as dh_inner_data_reader:
        dh_inner_data_reader.read(20)  # hashsum
        code = dh_inner_data_reader.read_int(signed=False)
        if code != 0xb5890dba:
            raise AssertionError('Invalid DH Inner Data code: {}'.format(code))

        nonce_from_server1 = dh_inner_data_reader.read(16)
        if nonce_from_server1 != nonce:
            raise AssertionError('Invalid nonce in encrypted answer')

        server_nonce_from_server1 = dh_inner_data_reader.read(16)
        if server_nonce_from_server1 != server_nonce:
            raise AssertionError('Invalid server nonce in encrypted answer')

        g = dh_inner_data_reader.read_int()
        dh_prime = get_int(dh_inner_data_reader.tgread_bytes(), signed=False)
        ga = get_int(dh_inner_data_reader.tgread_bytes(), signed=False)

        server_time = dh_inner_data_reader.read_int()
        time_offset = server_time - int(time.time())

    b = get_int(os.urandom(2048), signed=False)
    gb = pow(g, b, dh_prime)
    gab = pow(ga, b, dh_prime)

    # Prepare client DH Inner Data
    with BinaryWriter() as client_dh_inner_data_writer:
        client_dh_inner_data_writer.write_int(
            0x6643b654, signed=False)  # Client DH Inner Data
        client_dh_inner_data_writer.write(nonce)
        client_dh_inner_data_writer.write(server_nonce)
        client_dh_inner_data_writer.write_long(0)  # TODO retry_id
        client_dh_inner_data_writer.tgwrite_bytes(
            get_byte_array(
                gb, signed=False))

        with BinaryWriter() as client_dh_inner_data_with_hash_writer:
            client_dh_inner_data_with_hash_writer.write(
                utils.sha1(client_dh_inner_data_writer.get_bytes()))
            client_dh_inner_data_with_hash_writer.write(
                client_dh_inner_data_writer.get_bytes())
            client_dh_inner_data_bytes = client_dh_inner_data_with_hash_writer.get_bytes(
            )

    # Encryption
    client_dh_inner_data_encrypted_bytes = AES.encrypt_ige(
        client_dh_inner_data_bytes, key, iv)

    # Prepare Set client DH params
    with BinaryWriter() as set_client_dh_params_writer:
        set_client_dh_params_writer.write_int(0xf5045f1f, signed=False)
        set_client_dh_params_writer.write(nonce)
        set_client_dh_params_writer.write(server_nonce)
        set_client_dh_params_writer.tgwrite_bytes(
            client_dh_inner_data_encrypted_bytes)

        set_client_dh_params_bytes = set_client_dh_params_writer.get_bytes()
        sender.send(set_client_dh_params_bytes)

    # Step 3 response: Complete DH Exchange
    with BinaryReader(sender.receive()) as reader:
        code = reader.read_int(signed=False)
        if code == 0x3bcbf734:  # DH Gen OK
            nonce_from_server = reader.read(16)
            if nonce_from_server != nonce:
                raise NotImplementedError('Invalid nonce from server')

            server_nonce_from_server = reader.read(16)
            if server_nonce_from_server != server_nonce:
                raise NotImplementedError('Invalid server nonce from server')

            new_nonce_hash1 = reader.read(16)
            auth_key = AuthKey(get_byte_array(gab, signed=False))

            new_nonce_hash_calculated = auth_key.calc_new_nonce_hash(new_nonce,
                                                                     1)
            if new_nonce_hash1 != new_nonce_hash_calculated:
                raise AssertionError('Invalid new nonce hash')

            return auth_key, time_offset

        elif code == 0x46dc1fb9:  # DH Gen Retry
            raise NotImplementedError('dh_gen_retry')

        elif code == 0xa69dae02:  # DH Gen Fail
            raise NotImplementedError('dh_gen_fail')

        else:
            raise AssertionError('DH Gen unknown: {}'.format(hex(code)))
Beispiel #22
0
 async def set_auth_key(self, auth_key: AuthKey):
     self._auth_key = AuthKey(data=auth_key)
     await self._update_session_table()