From 9242e5fe6af6aeb768d571b5896274f4060db3b2 Mon Sep 17 00:00:00 2001 From: BarsTiger Date: Wed, 10 May 2023 23:51:23 +0300 Subject: [PATCH] Initial commit --- .gitignore | 5 ++ README.md | 5 ++ TelegramSessionKeeper.py | 6 ++ TelegramSessionKeeper.spec | 44 +++++++++++++ modules/__init__.py | 0 modules/client/__init__.py | 1 + modules/client/client.py | 19 ++++++ modules/config/__init__.py | 1 + modules/config/db.py | 17 +++++ modules/config/models.py | 15 +++++ modules/custom_items/DynamicSubmenu.py | 65 +++++++++++++++++++ modules/custom_items/__init__.py | 1 + modules/decorators/__init__.py | 0 modules/decorators/callback.py | 20 ++++++ modules/menu/__init__.py | 1 + modules/menu/callbacks/__init__.py | 0 modules/menu/callbacks/config/__init__.py | 1 + modules/menu/callbacks/config/callbacks.py | 16 +++++ .../menu/callbacks/create_session/__init__.py | 0 .../callbacks/create_session/callbacks.py | 33 ++++++++++ modules/menu/callbacks/get_code/__init__.py | 1 + modules/menu/callbacks/get_code/get_code.py | 6 ++ modules/menu/dynamic/__init__.py | 0 modules/menu/dynamic/get_code/__init__.py | 1 + modules/menu/dynamic/get_code/generator.py | 22 +++++++ modules/menu/dynamic/get_code/submenu.py | 15 +++++ modules/menu/fill.py | 7 ++ modules/menu/items/__init__.py | 0 modules/menu/items/config/__init__.py | 1 + modules/menu/items/config/fields.py | 20 ++++++ modules/menu/items/config/submenu.py | 17 +++++ modules/menu/items/create_session/__init__.py | 1 + modules/menu/items/create_session/fields.py | 7 ++ modules/menu/items/main.py | 10 +++ modules/menu/menu.py | 6 ++ requirements.txt | 6 ++ 36 files changed, 370 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 TelegramSessionKeeper.py create mode 100644 TelegramSessionKeeper.spec create mode 100644 modules/__init__.py create mode 100644 modules/client/__init__.py create mode 100644 modules/client/client.py create mode 100644 modules/config/__init__.py create mode 100644 modules/config/db.py create mode 100644 modules/config/models.py create mode 100644 modules/custom_items/DynamicSubmenu.py create mode 100644 modules/custom_items/__init__.py create mode 100644 modules/decorators/__init__.py create mode 100644 modules/decorators/callback.py create mode 100644 modules/menu/__init__.py create mode 100644 modules/menu/callbacks/__init__.py create mode 100644 modules/menu/callbacks/config/__init__.py create mode 100644 modules/menu/callbacks/config/callbacks.py create mode 100644 modules/menu/callbacks/create_session/__init__.py create mode 100644 modules/menu/callbacks/create_session/callbacks.py create mode 100644 modules/menu/callbacks/get_code/__init__.py create mode 100644 modules/menu/callbacks/get_code/get_code.py create mode 100644 modules/menu/dynamic/__init__.py create mode 100644 modules/menu/dynamic/get_code/__init__.py create mode 100644 modules/menu/dynamic/get_code/generator.py create mode 100644 modules/menu/dynamic/get_code/submenu.py create mode 100644 modules/menu/fill.py create mode 100644 modules/menu/items/__init__.py create mode 100644 modules/menu/items/config/__init__.py create mode 100644 modules/menu/items/config/fields.py create mode 100644 modules/menu/items/config/submenu.py create mode 100644 modules/menu/items/create_session/__init__.py create mode 100644 modules/menu/items/create_session/fields.py create mode 100644 modules/menu/items/main.py create mode 100644 modules/menu/menu.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a4eac10 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/dist/ +/build/ +/venv/ +config.storage +*.session diff --git a/README.md b/README.md new file mode 100644 index 0000000..1663c56 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Bars's Session Keeper +Simple telegram session generator and keeper, that can get activation code. + +## Tip +Move build of this app and .session files on encrypted flash drive to keep them safe. diff --git a/TelegramSessionKeeper.py b/TelegramSessionKeeper.py new file mode 100644 index 0000000..e0a7028 --- /dev/null +++ b/TelegramSessionKeeper.py @@ -0,0 +1,6 @@ +from modules.menu import menu +from modules.menu.fill import fill_menu + + +fill_menu() +menu.show() diff --git a/TelegramSessionKeeper.spec b/TelegramSessionKeeper.spec new file mode 100644 index 0000000..656f13f --- /dev/null +++ b/TelegramSessionKeeper.spec @@ -0,0 +1,44 @@ +# -*- mode: python ; coding: utf-8 -*- + + +block_cipher = None + + +a = Analysis( + ['TelegramSessionKeeper.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + [], + name='TelegramSessionKeeper', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/client/__init__.py b/modules/client/__init__.py new file mode 100644 index 0000000..38e2046 --- /dev/null +++ b/modules/client/__init__.py @@ -0,0 +1 @@ +from .client import GeneratedClient diff --git a/modules/client/client.py b/modules/client/client.py new file mode 100644 index 0000000..cd34dd2 --- /dev/null +++ b/modules/client/client.py @@ -0,0 +1,19 @@ +from ..config import config +from pyrogram import Client + + +class GeneratedClient(Client): + def __init__(self, name: str): + if not config.get('api_id'): + config['api_id'] = input('api_id from my.telegram.org: ') + if not config.get('api_hash'): + config['api_hash'] = input('api_hash from my.telegram.org: ') + + super().__init__( + name=name, + api_id=config['api_id'], + api_hash=config['api_hash'], + device_model=config.get('device_model', 'Session Keeper'), + app_version=config.get('app_version', 'DO NOT DEAUTH THIS SESSION'), + system_version=config.get('system_version', 'Bars\'s TelegramSessionKeeper') + ) diff --git a/modules/config/__init__.py b/modules/config/__init__.py new file mode 100644 index 0000000..2913ab3 --- /dev/null +++ b/modules/config/__init__.py @@ -0,0 +1 @@ +from .db import config, sessions diff --git a/modules/config/db.py b/modules/config/db.py new file mode 100644 index 0000000..ace5887 --- /dev/null +++ b/modules/config/db.py @@ -0,0 +1,17 @@ +import sqlitedict +import json + + +class ConfigDatabase(sqlitedict.SqliteDict): + def __init__(self, tablename): + super().__init__( + filename='config.storage', + tablename=tablename, + encode=json.dumps, + decode=json.loads, + autocommit=True + ) + + +config = ConfigDatabase('config') +sessions = ConfigDatabase('sessions') diff --git a/modules/config/models.py b/modules/config/models.py new file mode 100644 index 0000000..5a431cf --- /dev/null +++ b/modules/config/models.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass, asdict + + +@dataclass +class SessionConfig: + def __str__(self): + return f'{self.phone} - {self.id} - {self.profile_name} {f"- @{self.username}" if self.username else ""}' + + def json(self): + return asdict(self) + + phone: str + profile_name: str + id: int + username: str | None = None diff --git a/modules/custom_items/DynamicSubmenu.py b/modules/custom_items/DynamicSubmenu.py new file mode 100644 index 0000000..1976acd --- /dev/null +++ b/modules/custom_items/DynamicSubmenu.py @@ -0,0 +1,65 @@ +from cursesmenu.items import MenuItem +from cursesmenu.curses_menu import CursesMenu +from typing import Callable, Any + + +class DynamicSubmenuItem(MenuItem): + def __init__( + self, + text: str, + generator: Callable[..., CursesMenu], + menu: CursesMenu | None = None, + args: list[Any] | None = None, + kwargs: dict[Any, Any] | None = None, + ) -> None: + self._args: list[Any] | None = args + self._kwargs: dict[Any, Any] | None = kwargs + self._generator: Callable[..., CursesMenu] | None = generator + self._menu: CursesMenu | None = menu + self._submenu: CursesMenu | None = None + super().__init__( + text=text, + menu=menu + ) + + @property + def submenu(self) -> CursesMenu | None: + return self._submenu + + @submenu.setter + def submenu(self, submenu: CursesMenu | None) -> None: + self._submenu = submenu + if self._submenu is not None: + self._submenu.parent = self._menu + + @property + def menu(self) -> CursesMenu | None: + return self._menu + + @menu.setter + def menu(self, menu: CursesMenu | None) -> None: + self._menu = menu + if self._submenu is not None: + self._submenu.parent = menu + + def set_up(self) -> None: + assert self.menu is not None + self.menu.pause() + self.menu.clear_screen() + + def action(self) -> None: + self.submenu = self._generator(*self._args if self._args else [], + **self._kwargs if self._kwargs else {}) + self.submenu.start() + + def clean_up(self) -> None: + assert self.menu is not None + assert self.submenu is not None + self.submenu.join() + self.submenu.clear_screen() + self.menu.resume() + + def get_return(self) -> Any: + if self.submenu is not None: + return self.submenu.returned_value + return None diff --git a/modules/custom_items/__init__.py b/modules/custom_items/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/modules/custom_items/__init__.py @@ -0,0 +1 @@ +pass diff --git a/modules/decorators/__init__.py b/modules/decorators/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/decorators/callback.py b/modules/decorators/callback.py new file mode 100644 index 0000000..df71c14 --- /dev/null +++ b/modules/decorators/callback.py @@ -0,0 +1,20 @@ +from modules.menu.menu import menu + + +def callback(f): + def wrapper(*args, **kwargs): + menu.pause() + f(*args, **kwargs) + menu.resume() + + return wrapper + + +def async_callback(f): + def wrapper(*args, **kwargs): + import asyncio + menu.pause() + asyncio.run(f(*args, **kwargs)) + menu.resume() + + return wrapper diff --git a/modules/menu/__init__.py b/modules/menu/__init__.py new file mode 100644 index 0000000..a8bbe3f --- /dev/null +++ b/modules/menu/__init__.py @@ -0,0 +1 @@ +from .menu import menu diff --git a/modules/menu/callbacks/__init__.py b/modules/menu/callbacks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/menu/callbacks/config/__init__.py b/modules/menu/callbacks/config/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/modules/menu/callbacks/config/__init__.py @@ -0,0 +1 @@ +pass diff --git a/modules/menu/callbacks/config/callbacks.py b/modules/menu/callbacks/config/callbacks.py new file mode 100644 index 0000000..76287cb --- /dev/null +++ b/modules/menu/callbacks/config/callbacks.py @@ -0,0 +1,16 @@ +from modules.decorators.callback import callback +from modules.config import config + + +@callback +def edit_config_callback(field: str, comments: str, default: str = None): + print(f'Current value is {config.get(field)}') + print(f'Default value is {default}. Press Enter to restore it') + config[field] = input(f'{field} ({comments}) > ') + if config[field] in ['None', 'none']: + del config[field] + + if config[field] == '' and default is not None: + config[field] = default + elif default is None: + del config[field] diff --git a/modules/menu/callbacks/create_session/__init__.py b/modules/menu/callbacks/create_session/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/menu/callbacks/create_session/callbacks.py b/modules/menu/callbacks/create_session/callbacks.py new file mode 100644 index 0000000..ce9a75f --- /dev/null +++ b/modules/menu/callbacks/create_session/callbacks.py @@ -0,0 +1,33 @@ +from sqlite3 import OperationalError +from rich import print +from modules.decorators.callback import async_callback +from modules.client import GeneratedClient +from modules.config import sessions +from modules.config.models import SessionConfig + + +@async_callback +async def create_session_callback(): + session_name = input('New session name: ') + while session_name in sessions.keys(): + session_name = input('Session with this name is already saved. Try another name: ') + + try: + await (client := GeneratedClient(name=session_name)).start() + sessions[session_name] = SessionConfig( + id=client.me.id, + phone=client.phone_number, + profile_name=client.me.first_name + (f' {client.me.last_name}' if client.me.last_name else ''), + username=client.me.username + ).json() + print(f'[green]Created[/] session {session_name}...') + input() + + except OperationalError: + print('[red]Cannot create session file.[/] Try using different name...') + input() + + except Exception as e: + print(f'[red]Error:[/] {e}...') + input() + return diff --git a/modules/menu/callbacks/get_code/__init__.py b/modules/menu/callbacks/get_code/__init__.py new file mode 100644 index 0000000..a2ae2a9 --- /dev/null +++ b/modules/menu/callbacks/get_code/__init__.py @@ -0,0 +1 @@ +from .get_code import get_code_callback diff --git a/modules/menu/callbacks/get_code/get_code.py b/modules/menu/callbacks/get_code/get_code.py new file mode 100644 index 0000000..36761b0 --- /dev/null +++ b/modules/menu/callbacks/get_code/get_code.py @@ -0,0 +1,6 @@ +from modules.decorators.callback import async_callback + + +@async_callback +async def get_code_callback(session_name: str): + ... diff --git a/modules/menu/dynamic/__init__.py b/modules/menu/dynamic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/menu/dynamic/get_code/__init__.py b/modules/menu/dynamic/get_code/__init__.py new file mode 100644 index 0000000..38e0cfc --- /dev/null +++ b/modules/menu/dynamic/get_code/__init__.py @@ -0,0 +1 @@ +from .submenu import get_code_submenu_item diff --git a/modules/menu/dynamic/get_code/generator.py b/modules/menu/dynamic/get_code/generator.py new file mode 100644 index 0000000..af8e14f --- /dev/null +++ b/modules/menu/dynamic/get_code/generator.py @@ -0,0 +1,22 @@ +import os +from cursesmenu import CursesMenu +from cursesmenu.items import FunctionItem + +from modules.config import sessions +from modules.config.models import SessionConfig +from ...callbacks.get_code import get_code_callback + + +def generate_get_code_menu() -> CursesMenu: + submenu = CursesMenu( + title='Sessions' + ) + for session_name in sessions.keys(): + if os.path.isfile(f'{session_name}.session'): + submenu.items.append(FunctionItem( + f'{session_name} - {SessionConfig(**sessions[session_name])}', + function=get_code_callback, + args=[session_name] + )) + + return submenu diff --git a/modules/menu/dynamic/get_code/submenu.py b/modules/menu/dynamic/get_code/submenu.py new file mode 100644 index 0000000..1a0a347 --- /dev/null +++ b/modules/menu/dynamic/get_code/submenu.py @@ -0,0 +1,15 @@ +from ...menu import menu +from cursesmenu import CursesMenu +from modules.custom_items.DynamicSubmenu import DynamicSubmenuItem +from .generator import generate_get_code_menu + + +get_code_submenu = CursesMenu( + title='Sessions' +) + +get_code_submenu_item = DynamicSubmenuItem( + text='Get confirmation code', + generator=generate_get_code_menu, + menu=menu +) diff --git a/modules/menu/fill.py b/modules/menu/fill.py new file mode 100644 index 0000000..7f7ab39 --- /dev/null +++ b/modules/menu/fill.py @@ -0,0 +1,7 @@ +from .menu import menu + + +def fill_menu(): + from .items.main import items_list + for item in items_list: + menu.items.append(item) diff --git a/modules/menu/items/__init__.py b/modules/menu/items/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/menu/items/config/__init__.py b/modules/menu/items/config/__init__.py new file mode 100644 index 0000000..2add8b9 --- /dev/null +++ b/modules/menu/items/config/__init__.py @@ -0,0 +1 @@ +from .submenu import config_submenu_item diff --git a/modules/menu/items/config/fields.py b/modules/menu/items/config/fields.py new file mode 100644 index 0000000..433f55e --- /dev/null +++ b/modules/menu/items/config/fields.py @@ -0,0 +1,20 @@ +from cursesmenu.items import FunctionItem +from ...callbacks.config.callbacks import edit_config_callback + + +items_list = [ + FunctionItem('app_id', function=edit_config_callback, + args=['app_id', 'Telegram app_id, can be obtained on my.telegram.org']), + FunctionItem('api_hash', function=edit_config_callback, + args=['api_hash', 'Telegram api_hash, can be obtained on my.telegram.org']), + FunctionItem('device_model', function=edit_config_callback, + args=['device_model', 'Device model is first line of information about login in devices settings. ', + 'Session Keeper']), + FunctionItem('app_version', function=edit_config_callback, + args=['app_version', 'App version is second line of information about login in devices settings.', + 'DO NOT DEAUTH THIS SESSION']), + FunctionItem('system_version', function=edit_config_callback, + args=['system_version', + 'App version is shown in detailed information about login in devices settings. ', + 'Bars\'s TelegramSessionKeeper']), +] diff --git a/modules/menu/items/config/submenu.py b/modules/menu/items/config/submenu.py new file mode 100644 index 0000000..6fb1ec2 --- /dev/null +++ b/modules/menu/items/config/submenu.py @@ -0,0 +1,17 @@ +from ...menu import menu +from cursesmenu import CursesMenu +from cursesmenu.items import SubmenuItem +from .fields import items_list + + +config_submenu = CursesMenu( + title='Config' +) +for item in items_list: + config_submenu.items.append(item) + +config_submenu_item = SubmenuItem( + text='Edit config', + submenu=config_submenu, + menu=menu +) diff --git a/modules/menu/items/create_session/__init__.py b/modules/menu/items/create_session/__init__.py new file mode 100644 index 0000000..33be218 --- /dev/null +++ b/modules/menu/items/create_session/__init__.py @@ -0,0 +1 @@ +from .fields import create_new_session_item diff --git a/modules/menu/items/create_session/fields.py b/modules/menu/items/create_session/fields.py new file mode 100644 index 0000000..514ac74 --- /dev/null +++ b/modules/menu/items/create_session/fields.py @@ -0,0 +1,7 @@ +from cursesmenu.items import FunctionItem +from ...callbacks.create_session.callbacks import create_session_callback + + +create_new_session_item = FunctionItem( + 'Add new session', function=create_session_callback +) diff --git a/modules/menu/items/main.py b/modules/menu/items/main.py new file mode 100644 index 0000000..197d9e7 --- /dev/null +++ b/modules/menu/items/main.py @@ -0,0 +1,10 @@ +from .config import config_submenu_item +from .create_session import create_new_session_item +from ..dynamic.get_code import get_code_submenu_item + + +items_list = [ + create_new_session_item, + get_code_submenu_item, + config_submenu_item +] diff --git a/modules/menu/menu.py b/modules/menu/menu.py new file mode 100644 index 0000000..1f1230e --- /dev/null +++ b/modules/menu/menu.py @@ -0,0 +1,6 @@ +import cursesmenu + + +menu = cursesmenu.CursesMenu( + title='SessionKeeper' +) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1da8489 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +pyrogram +tgcrypto +sqlitedict +curses-menu +rich +pyinstaller \ No newline at end of file