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))
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
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)
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())
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
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)
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
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)
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, }
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
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)))
async def set_auth_key(self, auth_key: AuthKey): self._auth_key = AuthKey(data=auth_key) await self._update_session_table()