Initial commit

This commit is contained in:
BarsTiger
2023-05-10 23:51:23 +03:00
commit 9242e5fe6a
36 changed files with 370 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/dist/
/build/
/venv/
config.storage
*.session

5
README.md Normal file
View File

@@ -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.

6
TelegramSessionKeeper.py Normal file
View File

@@ -0,0 +1,6 @@
from modules.menu import menu
from modules.menu.fill import fill_menu
fill_menu()
menu.show()

View File

@@ -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,
)

0
modules/__init__.py Normal file
View File

View File

@@ -0,0 +1 @@
from .client import GeneratedClient

19
modules/client/client.py Normal file
View File

@@ -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')
)

View File

@@ -0,0 +1 @@
from .db import config, sessions

17
modules/config/db.py Normal file
View File

@@ -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')

15
modules/config/models.py Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
pass

View File

View File

@@ -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

1
modules/menu/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .menu import menu

View File

View File

@@ -0,0 +1 @@
pass

View File

@@ -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]

View File

@@ -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

View File

@@ -0,0 +1 @@
from .get_code import get_code_callback

View File

@@ -0,0 +1,6 @@
from modules.decorators.callback import async_callback
@async_callback
async def get_code_callback(session_name: str):
...

View File

View File

@@ -0,0 +1 @@
from .submenu import get_code_submenu_item

View File

@@ -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

View File

@@ -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
)

7
modules/menu/fill.py Normal file
View File

@@ -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)

View File

View File

@@ -0,0 +1 @@
from .submenu import config_submenu_item

View File

@@ -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']),
]

View File

@@ -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
)

View File

@@ -0,0 +1 @@
from .fields import create_new_session_item

View File

@@ -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
)

View File

@@ -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
]

6
modules/menu/menu.py Normal file
View File

@@ -0,0 +1,6 @@
import cursesmenu
menu = cursesmenu.CursesMenu(
title='SessionKeeper'
)

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
pyrogram
tgcrypto
sqlitedict
curses-menu
rich
pyinstaller