#!/usr/bin/env python3 """Provision once with owner credentials; save the bot token to a private JSON file.""" import argparse import json import os from pathlib import Path import sys import httpx def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--name', required=True) parser.add_argument('--slug', required=True) parser.add_argument('--description', default='') parser.add_argument('--output', type=Path, default=Path('bot-credentials.json')) args = parser.parse_args() base = os.environ.get('BOT_API_URL', 'https://botovod.srgkslv.ru').rstrip('/') email = os.environ.get('BOTOVOD_EMAIL', '') password = os.environ.get('BOTOVOD_PASSWORD', '') if not email or not password: sys.exit('Set BOTOVOD_EMAIL and BOTOVOD_PASSWORD for provisioning only.') # Reserve a private output before creating anything; never overwrite an existing token. try: fd = os.open(args.output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) except FileExistsError: sys.exit(f'{args.output} already exists. Reuse its token; do not create another bot.') try: with os.fdopen(fd, 'w', encoding='utf-8') as output: with httpx.Client(base_url=base, timeout=30, follow_redirects=False) as client: login = client.post('/api/admin/session', json={'email': email, 'password': password}) if login.status_code != 200: sys.exit(f'Provisioning login failed (HTTP {login.status_code}).') csrf = {'X-CSRF-Token': login.json()['csrf_token']} try: response = client.post('/api/admin/bots', headers=csrf, json={ 'name': args.name, 'slug': args.slug, 'description': args.description, 'quick_commands': ['status', 'help'], }) if response.status_code == 409: sys.exit('Bot slug already exists. Recover its saved runtime token; do not rotate automatically.') if response.status_code != 201: sys.exit(f'Create failed (HTTP {response.status_code}); inspect the request without logging credentials.') bot = response.json() # Persist immediately; do not print the token or include owner credentials. json.dump({'api_url': base, 'slug': bot['slug'], 'token': bot['token']}, output, indent=2) output.flush() os.fsync(output.fileno()) finally: try: client.delete('/api/admin/session', headers=csrf) except httpx.HTTPError: pass print(f"Bot created: {base}/bots/{args.slug}. Credentials saved to {args.output}; keep this file private.") except BaseException: # Preserve any written token if a later step failed. An empty file contains no credentials. if args.output.exists() and args.output.stat().st_size == 0: args.output.unlink() raise if __name__ == '__main__': main()