mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-31 07:57:38 +03:00 
			
		
		
		
	Create a StringSession
This commit is contained in:
		
							parent
							
								
									63174ae404
								
							
						
					
					
						commit
						0011f19f8b
					
				|  | @ -36,8 +36,9 @@ If you're not going to work with updates, or don't need to cache the | |||
| ``access_hash`` associated with the entities' ID, you can disable this | ||||
| by setting ``client.session.save_entities = False``. | ||||
| 
 | ||||
| Custom Session Storage | ||||
| ---------------------- | ||||
| 
 | ||||
| Different Session Storage | ||||
| ************************* | ||||
| 
 | ||||
| If you don't want to use the default SQLite session storage, you can also use | ||||
| one of the other implementations or implement your own storage. | ||||
|  | @ -46,89 +47,100 @@ To use a custom session storage, simply pass the custom session instance to | |||
| :ref:`TelegramClient <telethon-client>` instead of | ||||
| the session name. | ||||
| 
 | ||||
| Telethon contains two implementations of the abstract ``Session`` class: | ||||
| Telethon contains three implementations of the abstract ``Session`` class: | ||||
| 
 | ||||
| * ``MemorySession``: stores session data in Python variables. | ||||
| * ``SQLiteSession``, (default): stores sessions in their own SQLite databases. | ||||
| * ``MemorySession``: stores session data within memory. | ||||
| * ``SQLiteSession``: stores sessions within on-disk SQLite databases. Default. | ||||
| * ``StringSession``: stores session data within memory, | ||||
|   but can be saved as a string. | ||||
| 
 | ||||
| You can import these ``from telethon.sessions``. For example, using the | ||||
| ``StringSession`` is done as follows: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from telethon.sync import TelegramClient | ||||
|     from telethon.sessions import StringSession | ||||
| 
 | ||||
|     with TelegramClient(StringSession(string), api_id, api_hash) as client: | ||||
|         ...  # use the client | ||||
| 
 | ||||
|         # Save the string session as a string; you should decide how | ||||
|         # you want to save this information (over a socket, remote | ||||
|         # database, print it and then paste the string in the code, | ||||
|         # etc.); the advantage is that you don't need to save it | ||||
|         # on the current disk as a separate file, and can be reused | ||||
|         # anywhere else once you log in. | ||||
|         string = client.session.save() | ||||
| 
 | ||||
|     # Note that it's also possible to save any other session type | ||||
|     # as a string by using ``StringSession.save(session_instance)``: | ||||
|     client = TelegramClient('sqlite-session', api_id, api_hash) | ||||
|     string = StringSession.save(client.session) | ||||
| 
 | ||||
| There are other community-maintained implementations available: | ||||
| 
 | ||||
| * `SQLAlchemy <https://github.com/tulir/telethon-session-sqlalchemy>`_: stores all sessions in a single database via SQLAlchemy. | ||||
| * `Redis <https://github.com/ezdev128/telethon-session-redis>`_: stores all sessions in a single Redis data store. | ||||
| * `SQLAlchemy <https://github.com/tulir/telethon-session-sqlalchemy>`_: | ||||
|   stores all sessions in a single database via SQLAlchemy. | ||||
| 
 | ||||
| Creating your own storage | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| * `Redis <https://github.com/ezdev128/telethon-session-redis>`_: | ||||
|   stores all sessions in a single Redis data store. | ||||
| 
 | ||||
| The easiest way to create your own storage implementation is to use ``MemorySession`` | ||||
| as the base and check out how ``SQLiteSession`` or one of the community-maintained | ||||
| implementations work. You can find the relevant Python files under the ``sessions`` | ||||
| directory in Telethon. | ||||
| Creating your Own Storage | ||||
| ************************* | ||||
| 
 | ||||
| After you have made your own implementation, you can add it to the community-maintained | ||||
| session implementation list above with a pull request. | ||||
| The easiest way to create your own storage implementation is to use | ||||
| ``MemorySession`` as the base and check out how ``SQLiteSession`` or | ||||
| one of the community-maintained implementations work. You can find the | ||||
| relevant Python files under the ``sessions`` directory in Telethon. | ||||
| 
 | ||||
| SQLite Sessions and Heroku | ||||
| -------------------------- | ||||
| 
 | ||||
| You probably have a newer version of SQLite installed (>= 3.8.2). Heroku uses | ||||
| SQLite 3.7.9 which does not support ``WITHOUT ROWID``. So, if you generated | ||||
| your session file on a system with SQLite >= 3.8.2 your session file will not | ||||
| work on Heroku's platform and will throw a corrupted schema error. | ||||
| 
 | ||||
| There are multiple ways to solve this, the easiest of which is generating a | ||||
| session file on your Heroku dyno itself. The most complicated is creating | ||||
| a custom buildpack to install SQLite >= 3.8.2. | ||||
| After you have made your own implementation, you can add it to the | ||||
| community-maintained session implementation list above with a pull request. | ||||
| 
 | ||||
| 
 | ||||
| Generating a SQLite Session File on a Heroku Dyno | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| String Sessions | ||||
| *************** | ||||
| 
 | ||||
| .. note:: | ||||
|     Due to Heroku's ephemeral filesystem all dynamically generated | ||||
|     files not part of your applications buildpack or codebase are destroyed | ||||
|     upon each restart. | ||||
| ``StringSession`` are a convenient way to embed your login credentials | ||||
| directly into your code for extremely easy portability, since all they | ||||
| take is a string to be able to login without asking for your phone and | ||||
| code (or faster start if you're using a bot token). | ||||
| 
 | ||||
| The easiest way to generate a string session is as follows: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from telethon.sync import TelegramClient | ||||
|     from telethon.sessions import StringSession | ||||
| 
 | ||||
|     with TelegramClient(StringSession(), api_id, api_hash) as client: | ||||
|         print(client.session.save()) | ||||
| 
 | ||||
| 
 | ||||
| Think of this as a way to export your authorization key (what's needed | ||||
| to login into your account). This will print a string in the standard | ||||
| output (likely your terminal). | ||||
| 
 | ||||
| .. warning:: | ||||
|     Do not restart your application Dyno at any point prior to retrieving your | ||||
|     session file. Constantly creating new session files from Telegram's API | ||||
|     will result in a 24 hour rate limit ban. | ||||
| 
 | ||||
| Due to Heroku's ephemeral filesystem all dynamically generated | ||||
| files not part of your applications buildpack or codebase are destroyed upon | ||||
| each restart. | ||||
|     **Keep this string safe!** Anyone with this string can use it | ||||
|     to login into your account and do anything they want to to do. | ||||
| 
 | ||||
| Using this scaffolded code we can start the authentication process: | ||||
|     This is similar to leaking your ``*.session`` files online, | ||||
|     but it is easier to leak a string than it is to leak a file. | ||||
| 
 | ||||
|     .. code-block:: python | ||||
| 
 | ||||
|         client = TelegramClient('login.session', api_id, api_hash).start() | ||||
| Once you have the string (which is a bit long), load it into your script | ||||
| somehow. You can use a normal text file and ``open(...).read()`` it or | ||||
| you can save it in a variable directly: | ||||
| 
 | ||||
| At this point your Dyno will crash because you cannot access stdin. Open your | ||||
| Dyno's control panel on the Heroku website and "Run console" from the "More" | ||||
| dropdown at the top right. Enter ``bash`` and wait for it to load. | ||||
| .. code-block:: python | ||||
| 
 | ||||
| You will automatically be placed into your applications working directory. | ||||
| So run your application ``python app.py`` and now you can complete the input | ||||
| requests such as "what is your phone number" etc. | ||||
|     string = '1aaNk8EX-YRfwoRsebUkugFvht6DUPi_Q25UOCzOAqzc...' | ||||
|     with TelegramClient(StringSession(string), api_id, api_hash) as client: | ||||
|         client.send_message('me', 'Hi') | ||||
| 
 | ||||
| Once you're successfully authenticated exit your application script with | ||||
| CTRL + C and ``ls`` to confirm ``login.session`` exists in your current | ||||
| directory. Now you can create a git repo on your account and commit | ||||
| ``login.session`` to that repo. | ||||
| 
 | ||||
| You cannot ``ssh`` into your Dyno instance because it has crashed, so unless | ||||
| you programatically upload this file to a server host this is the only way to | ||||
| get it off of your Dyno. | ||||
| 
 | ||||
| You now have a session file compatible with SQLite <= 3.8.2. Now you can | ||||
| programatically fetch this file from an external host (Firebase, S3 etc.) | ||||
| and login to your session using the following scaffolded code: | ||||
| 
 | ||||
|     .. code-block:: python | ||||
| 
 | ||||
|         fileName, headers = urllib.request.urlretrieve(file_url, 'login.session') | ||||
|         client = TelegramClient(os.path.abspath(fileName), api_id, api_hash).start() | ||||
| 
 | ||||
| .. note:: | ||||
|     - ``urlretrieve`` will be depreciated, consider using ``requests``. | ||||
|     - ``file_url`` represents the location of your file. | ||||
| These strings are really convenient for using in places like Heroku since | ||||
| their ephemeral filesystem will delete external files once your application | ||||
| is over. | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| from .abstract import Session | ||||
| from .memory import MemorySession | ||||
| from .sqlite import SQLiteSession | ||||
| from .string import StringSession | ||||
|  |  | |||
							
								
								
									
										43
									
								
								telethon/sessions/string.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								telethon/sessions/string.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| import base64 | ||||
| import ipaddress | ||||
| import struct | ||||
| 
 | ||||
| from .memory import MemorySession | ||||
| from ..crypto import AuthKey | ||||
| 
 | ||||
| CURRENT_VERSION = '1' | ||||
| 
 | ||||
| 
 | ||||
| class StringSession(MemorySession): | ||||
|     """ | ||||
|     This minimal session file can be easily saved and loaded as a string. | ||||
| 
 | ||||
|     It is thought to be used where you don't want to create any on-disk | ||||
|     files but would still like to be able to save and load existing sessions | ||||
|     by other means. | ||||
|     """ | ||||
|     def __init__(self, string=None): | ||||
|         super().__init__() | ||||
|         if string and string[0] != CURRENT_VERSION: | ||||
|             raise ValueError('Not a valid string') | ||||
| 
 | ||||
|         ip_len = 4 if len(string) == 353 else 16 | ||||
|         self._dc_id, ip, self._port, key = struct.unpack( | ||||
|             '>B{}sH256s'.format(ip_len), base64.urlsafe_b64decode(string[1:])) | ||||
| 
 | ||||
|         self._server_address = ipaddress.ip_address(ip).compressed | ||||
|         if any(key): | ||||
|             self._auth_key = AuthKey(key) | ||||
| 
 | ||||
|     def save(self): | ||||
|         if not self._auth_key: | ||||
|             return '' | ||||
| 
 | ||||
|         ip = ipaddress.ip_address(self._server_address).packed | ||||
|         return CURRENT_VERSION + base64.urlsafe_b64encode(struct.pack( | ||||
|             '>B{}sH256s'.format(len(ip)), | ||||
|             self._dc_id, | ||||
|             ip, | ||||
|             self._port, | ||||
|             self._auth_key.key | ||||
|         )).decode('ascii') | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user