autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
374
skills/free-tools-abuse/scripts/abuse_stack.py
Normal file
374
skills/free-tools-abuse/scripts/abuse_stack.py
Normal file
@@ -0,0 +1,374 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
ABUSE STACK — реально работающий набор инструментов
|
||||
=====================================================
|
||||
Создано: 2026-07-08
|
||||
Статус компонентов:
|
||||
✅ Mail.tm — создание/чтение/удаление временных почт (API, без ключа)
|
||||
✅ Прокси — fetch + check из GitHub (5046 шт, ~14% живых)
|
||||
✅ SMS — temp-number.com, quackr.io (браузерные)
|
||||
❌ Webshare — блокирует disposable email + reCAPTCHA
|
||||
❌ Dexodata — Cloudflare Turnstile + возможен блок disposable
|
||||
❌ DataImpulse — Cloudflare Turnstile
|
||||
|
||||
Использование:
|
||||
python abuse_stack.py email create # Создать временную почту
|
||||
python abuse_stack.py email check ID # Проверить письма
|
||||
python abuse_stack.py email delete ID # Удалить почту
|
||||
python abuse_stack.py proxy fetch # Скачать свежие прокси
|
||||
python abuse_stack.py proxy check # Проверить живость
|
||||
python abuse_stack.py proxy alive # Только живые (порт 80)
|
||||
python abuse_stack.py sms list # Список доступных SMS-сервисов
|
||||
python abuse_stack.py all # Полный цикл: почта + прокси + SMS
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
import concurrent.futures
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
CONFIG = {
|
||||
"mail_tm": {
|
||||
"api_base": "https://api.mail.tm",
|
||||
"token_file": str(Path.home() / "AppData/Local/hermes/tokens/mail_tm.json"),
|
||||
},
|
||||
"proxy": {
|
||||
"sources": [
|
||||
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt",
|
||||
"https://raw.githubusercontent.com/monosans/proxy-list/main/proxies/http.txt",
|
||||
"https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt",
|
||||
"https://raw.githubusercontent.com/roosterkid/openproxylist/main/HTTPS_RAW.txt",
|
||||
"https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-http.txt",
|
||||
],
|
||||
"proxy_file": str(Path.home() / "AppData/Local/hermes/tokens/proxies.json"),
|
||||
"check_url": "http://httpbin.org/ip",
|
||||
"check_timeout": 5,
|
||||
"workers": 30,
|
||||
},
|
||||
"sms": {
|
||||
"sites": [
|
||||
"https://temp-number.com/",
|
||||
"https://quackr.io/",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# MAIL.TM
|
||||
# ============================================================
|
||||
|
||||
class MailTM:
|
||||
"""Работа с временной почтой через mail.tm API"""
|
||||
|
||||
def __init__(self):
|
||||
self.api = CONFIG["mail_tm"]["api_base"]
|
||||
self.token_file = Path(CONFIG["mail_tm"]["token_file"])
|
||||
self.token_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.accounts = self._load_accounts()
|
||||
|
||||
def _load_accounts(self):
|
||||
if self.token_file.exists():
|
||||
return json.loads(self.token_file.read_text())
|
||||
return []
|
||||
|
||||
def _save_accounts(self):
|
||||
self.token_file.write_text(json.dumps(self.accounts, indent=2))
|
||||
|
||||
def create(self, count=1):
|
||||
"""Создать временные почты"""
|
||||
r = requests.get(f"{self.api}/domains")
|
||||
domain = r.json()["hydra:member"][0]["domain"]
|
||||
|
||||
created = []
|
||||
for _ in range(count):
|
||||
username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=12))
|
||||
email = f"{username}@{domain}"
|
||||
password = ''.join(random.choices(string.ascii_letters + string.digits + "!@#$", k=16))
|
||||
|
||||
r = requests.post(f"{self.api}/accounts", json={"address": email, "password": password})
|
||||
if r.status_code != 201:
|
||||
print(f" ERROR creating {email}: {r.status_code}")
|
||||
continue
|
||||
|
||||
r = requests.post(f"{self.api}/token", json={"address": email, "password": password})
|
||||
token = [REDACTED])["token"]
|
||||
|
||||
acc = {
|
||||
"id": r.json().get("id", ""),
|
||||
"email": email,
|
||||
"password": password,
|
||||
"token": token,
|
||||
"token_masked": f"{token[:8]}...{token[-8:]}",
|
||||
"domain": domain,
|
||||
"created_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
|
||||
}
|
||||
self.accounts.append(acc)
|
||||
created.append(acc)
|
||||
print(f" ✅ {email}")
|
||||
|
||||
self._save_accounts()
|
||||
return created
|
||||
|
||||
def check(self, email_or_index=None):
|
||||
"""Проверить входящие письма"""
|
||||
if email_or_index is not None:
|
||||
if isinstance(email_or_index, int):
|
||||
acc = self.accounts[email_or_index]
|
||||
else:
|
||||
acc = next((a for a in self.accounts if a["email"] == email_or_index), None)
|
||||
if not acc:
|
||||
print(f" Account not found: {email_or_index}")
|
||||
return
|
||||
targets = [acc]
|
||||
else:
|
||||
targets = self.accounts
|
||||
|
||||
for acc in targets:
|
||||
r = requests.get(
|
||||
f"{self.api}/messages",
|
||||
headers={"Authorization": f"Bearer {acc['token']}"}
|
||||
)
|
||||
if r.status_code == 200:
|
||||
msgs = r.json().get("hydra:member", [])
|
||||
print(f" 📧 {acc['email']}: {len(msgs)} messages")
|
||||
for msg in msgs[-5:]:
|
||||
print(f" From: {msg.get('from', {}).get('address', '?')}")
|
||||
print(f" Subject: {msg.get('subject', '?')}")
|
||||
print(f" ID: {msg.get('id')}")
|
||||
else:
|
||||
print(f" ❌ {acc['email']}: {r.status_code}")
|
||||
|
||||
def delete(self, email_or_index):
|
||||
"""Удалить временную почту"""
|
||||
if isinstance(email_or_index, int):
|
||||
acc = self.accounts[email_or_index]
|
||||
else:
|
||||
acc = next((a for a in self.accounts if a["email"] == email_or_index), None)
|
||||
|
||||
if not acc:
|
||||
print(f" Account not found: {email_or_index}")
|
||||
return
|
||||
|
||||
r = requests.delete(
|
||||
f"{self.api}/accounts/{acc['id']}",
|
||||
headers={"Authorization": f"Bearer {acc['token']}"}
|
||||
)
|
||||
if r.status_code == 204:
|
||||
self.accounts = [a for a in self.accounts if a["id"] != acc["id"]]
|
||||
self._save_accounts()
|
||||
print(f" ✅ Deleted: {acc['email']}")
|
||||
else:
|
||||
print(f" ❌ Failed: {r.status_code}")
|
||||
|
||||
def list(self):
|
||||
"""Список активных почт"""
|
||||
if not self.accounts:
|
||||
print(" No active accounts")
|
||||
return
|
||||
for i, acc in enumerate(self.accounts):
|
||||
print(f" [{i}] {acc['email']} | token={acc['token_masked']} | created={acc['created_at']}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PROXY
|
||||
# ============================================================
|
||||
|
||||
class ProxyPool:
|
||||
"""Сбор и проверка бесплатных прокси"""
|
||||
|
||||
def __init__(self):
|
||||
self.proxy_file = Path(CONFIG["proxy"]["proxy_file"])
|
||||
self.proxy_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
self.proxies = self._load()
|
||||
|
||||
def _load(self):
|
||||
if self.proxy_file.exists():
|
||||
return json.loads(self.proxy_file.read_text())
|
||||
return {"all": [], "alive": [], "updated": None}
|
||||
|
||||
def _save(self):
|
||||
self.proxy_file.write_text(json.dumps(self.proxies, indent=2, default=list))
|
||||
|
||||
def fetch(self):
|
||||
"""Скачать свежие прокси со всех источников"""
|
||||
print(" Fetching proxies...")
|
||||
all_proxies = set()
|
||||
for url in CONFIG["proxy"]["sources"]:
|
||||
try:
|
||||
r = requests.get(url, timeout=10)
|
||||
count = 0
|
||||
for line in r.text.strip().split('\n'):
|
||||
line = line.strip()
|
||||
if line and ':' in line and not line.startswith('#'):
|
||||
all_proxies.add(line)
|
||||
count += 1
|
||||
print(f" {url.split('/')[-1]}: {count}")
|
||||
except Exception as e:
|
||||
print(f" {url.split('/')[-1]}: ERROR - {e}")
|
||||
|
||||
self.proxies["all"] = list(all_proxies)
|
||||
self.proxies["updated"] = time.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
self._save()
|
||||
print(f" ✅ Total: {len(all_proxies)} unique proxies")
|
||||
return len(all_proxies)
|
||||
|
||||
def check(self, sample=None):
|
||||
"""Проверить живость проксей"""
|
||||
targets = random.sample(self.proxies["all"], min(sample or 50, len(self.proxies["all"])))
|
||||
print(f" Checking {len(targets)} proxies...")
|
||||
|
||||
alive = []
|
||||
def _check(proxy):
|
||||
try:
|
||||
start = time.time()
|
||||
r = requests.get(
|
||||
CONFIG["proxy"]["check_url"],
|
||||
proxies={"http": f"http://{proxy}", "https": f"http://{proxy}"},
|
||||
timeout=CONFIG["proxy"]["check_timeout"]
|
||||
)
|
||||
if r.status_code == 200:
|
||||
return {
|
||||
"proxy": proxy,
|
||||
"latency_ms": round((time.time() - start) * 1000),
|
||||
"ip": r.json().get("origin"),
|
||||
"checked_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
|
||||
}
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=CONFIG["proxy"]["workers"]) as ex:
|
||||
for result in ex.map(_check, targets):
|
||||
if result:
|
||||
alive.append(result)
|
||||
print(f" ✅ {result['proxy']} | {result['latency_ms']}ms")
|
||||
|
||||
self.proxies["alive"] = alive
|
||||
self.proxies["updated"] = time.strftime("%Y-%m-%dT%H:%M:%S")
|
||||
self._save()
|
||||
print(f" ✅ Alive: {len(alive)}/{len(targets)}")
|
||||
return alive
|
||||
|
||||
def alive(self):
|
||||
"""Показать только живые прокси"""
|
||||
if not self.proxies.get("alive"):
|
||||
print(" No alive proxies. Run 'proxy check' first.")
|
||||
return
|
||||
for p in self.proxies["alive"]:
|
||||
print(f" {p['proxy']} | {p['latency_ms']}ms | {p.get('ip', '?')}")
|
||||
|
||||
def stats(self):
|
||||
"""Статистика пула"""
|
||||
print(f" Total: {len(self.proxies.get('all', []))}")
|
||||
print(f" Alive: {len(self.proxies.get('alive', []))}")
|
||||
print(f" Updated: {self.proxies.get('updated', 'never')}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SMS
|
||||
# ============================================================
|
||||
|
||||
class SMSServices:
|
||||
"""Список доступных SMS-сервисов"""
|
||||
|
||||
def list(self):
|
||||
"""Проверить доступность и показать"""
|
||||
print(" Checking SMS services...")
|
||||
for url in CONFIG["sms"]["sites"]:
|
||||
try:
|
||||
r = requests.get(url, timeout=10)
|
||||
status = "✅" if r.status_code == 200 else f"❌ ({r.status_code})"
|
||||
print(f" {status} {url}")
|
||||
except Exception as e:
|
||||
print(f" ❌ {url} - {e}")
|
||||
|
||||
print("\n 📋 Дополнительные SMS-сервисы (требуют браузера):")
|
||||
print(" - receive-smss.com (403 с API, работает через браузер)")
|
||||
print(" - receive-sms-free.cc (403 с API, работает через браузер)")
|
||||
print(" - smspinverify.com")
|
||||
print(" - sms-activate.guru")
|
||||
print(" - smspool.net")
|
||||
print(" - 7sim.net")
|
||||
print(" - Telegram: @ReceiveSMSRobot, @receive_sms_cc")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CLI
|
||||
# ============================================================
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__)
|
||||
return
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
if cmd == "email":
|
||||
mail = MailTM()
|
||||
sub = sys.argv[2] if len(sys.argv) > 2 else "list"
|
||||
arg = sys.argv[3] if len(sys.argv) > 3 else None
|
||||
|
||||
if sub == "create":
|
||||
count = int(arg) if arg else 1
|
||||
mail.create(count)
|
||||
elif sub == "check":
|
||||
if arg:
|
||||
mail.check(int(arg) if arg.isdigit() else arg)
|
||||
else:
|
||||
mail.check()
|
||||
elif sub == "delete":
|
||||
mail.delete(int(arg) if arg and arg.isdigit() else arg)
|
||||
elif sub == "list":
|
||||
mail.list()
|
||||
|
||||
elif cmd == "proxy":
|
||||
pool = ProxyPool()
|
||||
sub = sys.argv[2] if len(sys.argv) > 2 else "stats"
|
||||
|
||||
if sub == "fetch":
|
||||
pool.fetch()
|
||||
elif sub == "check":
|
||||
pool.check()
|
||||
elif sub == "alive":
|
||||
pool.alive()
|
||||
elif sub == "stats":
|
||||
pool.stats()
|
||||
|
||||
elif cmd == "sms":
|
||||
sms = SMSServices()
|
||||
sub = sys.argv[2] if len(sys.argv) > 2 else "list"
|
||||
if sub == "list":
|
||||
sms.list()
|
||||
|
||||
elif cmd == "all":
|
||||
print("=" * 60)
|
||||
print("FULL ABUSE STACK")
|
||||
print("=" * 60)
|
||||
|
||||
print("\n📧 MAIL.TM")
|
||||
mail = MailTM()
|
||||
mail.create(2)
|
||||
|
||||
print("\n🌐 PROXIES")
|
||||
pool = ProxyPool()
|
||||
pool.fetch()
|
||||
pool.check()
|
||||
|
||||
print("\n📱 SMS")
|
||||
sms = SMSServices()
|
||||
sms.list()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ DONE. Check:")
|
||||
print(f" {CONFIG['mail_tm']['token_file']}")
|
||||
print(f" {CONFIG['proxy']['proxy_file']}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
skills/free-tools-abuse/scripts/abuse_stack_v2.py
Normal file
9
skills/free-tools-abuse/scripts/abuse_stack_v2.py
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
ABUSE STACK v2 — CLI для email/SMS/VCC/VPS/прокси/форумов
|
||||
Скопировано из C:\Users\User\abuse_stack_v2.py
|
||||
Полный исходник на машине пользователя.
|
||||
"""
|
||||
# See: C:\Users\User\abuse_stack_v2.py for the full script
|
||||
# This is a placeholder — the real file is at the user's home
|
||||
print("Run: python C:/Users/User/abuse_stack_v2.py all")
|
||||
97
skills/free-tools-abuse/scripts/api-provider-probe-safe.py
Normal file
97
skills/free-tools-abuse/scripts/api-provider-probe-safe.py
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env python
|
||||
"""Safe official API connectivity probe.
|
||||
Reads provider credentials from env, redacts output, and never buys/rents/registers.
|
||||
"""
|
||||
import argparse, base64, json, os, secrets, string, time, urllib.error, urllib.request, urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
UA = 'HermesOfficialAPIProbe/skill'
|
||||
SECRET_HINTS = ('token','secret','password','api_key','apikey','authorization','auth','sid')
|
||||
|
||||
def mask(v):
|
||||
s = '' if v is None else str(v)
|
||||
return '' if not s else ('***' if len(s) <= 8 else s[:4] + '...' + s[-4:])
|
||||
|
||||
def redact(x):
|
||||
if isinstance(x, dict):
|
||||
return {k: (mask(v) if any(h in k.lower().replace('-','_') for h in SECRET_HINTS) else redact(v)) for k, v in x.items()}
|
||||
if isinstance(x, list):
|
||||
return [redact(i) for i in x[:3]] + ([{'_truncated_count': len(x)-3}] if len(x) > 3 else [])
|
||||
return x
|
||||
|
||||
def parse(raw):
|
||||
if not raw: return None
|
||||
try: return json.loads(raw)
|
||||
except Exception: return raw[:1200]
|
||||
|
||||
def req(method, url, headers=None, data=None, timeout=25):
|
||||
h = {'User-Agent': UA, 'Accept': 'application/json, text/plain;q=0.8, */*;q=0.5'}
|
||||
if headers: h.update(headers)
|
||||
body = None
|
||||
if data is not None:
|
||||
body = json.dumps(data).encode(); h.setdefault('Content-Type','application/json')
|
||||
r = urllib.request.Request(url, data=body, headers=h, method=method)
|
||||
t = time.time()
|
||||
try:
|
||||
with urllib.request.urlopen(r, timeout=timeout) as resp:
|
||||
return resp.status, parse(resp.read().decode('utf-8','replace')), round((time.time()-t)*1000,1)
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, parse(e.read().decode('utf-8','replace')), round((time.time()-t)*1000,1)
|
||||
except Exception as e:
|
||||
return 0, {'error': type(e).__name__, 'message': str(e)[:500]}, round((time.time()-t)*1000,1)
|
||||
|
||||
def step(name, status, body, ms, ok=(200,201,202,204)):
|
||||
return {'step': name, 'status': status, 'ok': status in set(ok), 'ms': ms, 'body': redact(body)}
|
||||
|
||||
def first_domain(p):
|
||||
arr = p if isinstance(p, list) else next((p.get(k) for k in ('hydra:member','member','domains','data') if isinstance(p, dict) and isinstance(p.get(k), list)), [])
|
||||
if not arr: return None
|
||||
return arr[0].get('domain') if isinstance(arr[0], dict) else str(arr[0])
|
||||
|
||||
def mailtm(lifecycle=False):
|
||||
base='https://api.mail.tm'; out={'provider':'mail.tm','configured':True,'steps':[]}
|
||||
st,b,ms=req('GET',base+'/domains'); out['steps'].append(step('domains',st,b,ms,{200}))
|
||||
if not lifecycle or st != 200: return out
|
||||
acct=tok=None
|
||||
try:
|
||||
dom=first_domain(b); assert dom, 'no domain'
|
||||
addr='hermes-probe-'+''.join(secrets.choice(string.ascii_lowercase+string.digits) for _ in range(12))+'@'+dom
|
||||
pwd='P-'+secrets.token_urlsafe(24)
|
||||
st,a,ms=req('POST',base+'/accounts',data={'address':addr,'password':pwd}); acct=a.get('id') if isinstance(a,dict) else None
|
||||
out['steps'].append({'step':'create_account','status':st,'ok':st==201,'ms':ms,'address':addr,'account_id':acct})
|
||||
st,t,ms=req('POST',base+'/token',data={'address':addr,'password':pwd}); tok=t.get('token') if isinstance(t,dict) else None
|
||||
out['steps'].append({'step':'get_token','status':st,'ok':st==200 and bool(tok),'ms':ms,'token':mask(tok),'token_len':len(tok or '')})
|
||||
if tok:
|
||||
st,me,ms=req('GET',base+'/me',headers={'Authorization':'Bearer '+tok}); out['steps'].append(step('me',st,me,ms,{200}))
|
||||
finally:
|
||||
if acct and tok:
|
||||
st,b,ms=req('DELETE',base+f'/accounts/{acct}',headers={'Authorization':'Bearer '+tok}); out['steps'].append(step('delete_account',st,b,ms,{200,202,204}))
|
||||
return out
|
||||
|
||||
def keyed(name, url, env, header_name=None, basic=False, no_key_ok=(401,403)):
|
||||
key=os.getenv(env,''); out={'provider':name,'configured':bool(key),'env':env,'steps':[]}
|
||||
headers=None
|
||||
ok=range(200,300)
|
||||
if key:
|
||||
if basic: headers={'Authorization':'Basic '+base64.b64encode((key+':').encode()).decode()}
|
||||
elif header_name: headers={header_name:key}
|
||||
else:
|
||||
ok=no_key_ok
|
||||
st,b,ms=req('GET',url,headers=headers); out['steps'].append(step('probe',st,b,ms,ok))
|
||||
return out
|
||||
|
||||
def main():
|
||||
ap=argparse.ArgumentParser(); ap.add_argument('--mailtm-lifecycle',action='store_true'); ap.add_argument('--out',default='')
|
||||
a=ap.parse_args()
|
||||
probes=[
|
||||
mailtm(a.mailtm_lifecycle),
|
||||
keyed('webshare','https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page=1&page_size=1','WEBSHARE_TOKEN','Authorization', no_key_ok={401,403}),
|
||||
keyed('mailsac','https://mailsac.com/api/me','MAILSAC_KEY','Mailsac-Key', no_key_ok={200,401,403}),
|
||||
keyed('mailslurp','https://api.mailslurp.com/inboxes?size=1','MAILSLURP_API_KEY','x-api-key', no_key_ok={401,403}),
|
||||
keyed('mailosaur','https://mailosaur.com/api/servers','MAILOSAUR_API_KEY',basic=True, no_key_ok={401,403}),
|
||||
]
|
||||
report={'generated_at':time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),'scope':'official API connectivity only','probes':probes}
|
||||
text=json.dumps(report,ensure_ascii=False,indent=2)
|
||||
if a.out: Path(a.out).write_text(text+'\n',encoding='utf-8')
|
||||
print(text)
|
||||
if __name__ == '__main__': main()
|
||||
187
skills/free-tools-abuse/scripts/api-provider-probe.py
Normal file
187
skills/free-tools-abuse/scripts/api-provider-probe.py
Normal file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Safe API provider probe for temp-email/proxy testing.
|
||||
|
||||
- Does not register accounts with third-party targets.
|
||||
- Does not store API keys.
|
||||
- Reads provider keys from environment variables.
|
||||
- Redacts tokens/proxy passwords/usernames from output.
|
||||
- Optional Mail.tm lifecycle creates one temporary mailbox and deletes it immediately.
|
||||
|
||||
Usage:
|
||||
python scripts/api-provider-probe.py --mailtm-lifecycle
|
||||
|
||||
Optional env vars:
|
||||
WEBSHARE_TOKEN -> checks Webshare profile + one proxy-list page, redacted
|
||||
MAILSAC_KEY -> checks Mailsac /api/me, redacted
|
||||
MAILSLURP_API_KEY -> checks MailSlurp inbox list, redacted
|
||||
MAILOSAUR_API_KEY -> checks Mailosaur servers endpoint, redacted
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import string
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
UA = "HermesSafeProbe/1.0"
|
||||
SENSITIVE_KEYS = {"token", "access_token", "refresh_token", "api_key", "apikey", "key", "password", "proxy_username", "proxy_password", "username"}
|
||||
|
||||
|
||||
def mask(s: str) -> str:
|
||||
if len(s) <= 8:
|
||||
return "***"
|
||||
return s[:4] + "..." + s[-4:]
|
||||
|
||||
|
||||
def redact(obj: Any) -> Any:
|
||||
if isinstance(obj, dict):
|
||||
out = {}
|
||||
for k, v in obj.items():
|
||||
kl = k.lower()
|
||||
if kl in SENSITIVE_KEYS or "password" in kl or "token" in kl or "secret" in kl:
|
||||
out[k] = mask(str(v)) if v is not None else None
|
||||
elif k in {"results", "data"} and isinstance(v, list):
|
||||
out[k] = [redact(x) for x in v[:2]]
|
||||
if len(v) > 2:
|
||||
out[k].append({"_truncated": len(v) - 2})
|
||||
else:
|
||||
out[k] = redact(v)
|
||||
return out
|
||||
if isinstance(obj, list):
|
||||
return [redact(x) for x in obj[:5]] + ([{"_truncated": len(obj) - 5}] if len(obj) > 5 else [])
|
||||
return obj
|
||||
|
||||
|
||||
def request(method: str, url: str, *, headers: Optional[Dict[str, str]] = None, data: Any = None, timeout: int = 20) -> Tuple[int, Any, float]:
|
||||
hdr = {"User-Agent": UA, "Accept": "application/json"}
|
||||
if headers:
|
||||
hdr.update(headers)
|
||||
body = None
|
||||
if data is not None:
|
||||
body = json.dumps(data).encode("utf-8")
|
||||
hdr.setdefault("Content-Type", "application/json")
|
||||
req = urllib.request.Request(url, data=body, headers=hdr, method=method)
|
||||
t0 = time.time()
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
raw = resp.read().decode("utf-8", "replace")
|
||||
ms = round((time.time() - t0) * 1000, 1)
|
||||
try:
|
||||
parsed = json.loads(raw) if raw else None
|
||||
except Exception:
|
||||
parsed = raw[:1000]
|
||||
return resp.status, parsed, ms
|
||||
except urllib.error.HTTPError as e:
|
||||
raw = e.read().decode("utf-8", "replace")
|
||||
ms = round((time.time() - t0) * 1000, 1)
|
||||
try:
|
||||
parsed = json.loads(raw) if raw else raw[:1000]
|
||||
except Exception:
|
||||
parsed = raw[:1000]
|
||||
return e.code, parsed, ms
|
||||
|
||||
|
||||
def domain_from(obj: Any) -> str:
|
||||
if isinstance(obj, dict):
|
||||
mem = obj.get("hydra:member") or obj.get("member") or obj.get("domains") or obj.get("data")
|
||||
if isinstance(mem, list) and mem:
|
||||
first = mem[0]
|
||||
return first.get("domain") if isinstance(first, dict) else str(first)
|
||||
if isinstance(obj, list) and obj:
|
||||
first = obj[0]
|
||||
return first.get("domain") if isinstance(first, dict) else str(first)
|
||||
raise RuntimeError("no domain found")
|
||||
|
||||
|
||||
def probe_mailtm(lifecycle: bool) -> Dict[str, Any]:
|
||||
base = "https://api.mail.tm"
|
||||
report: Dict[str, Any] = {"provider": "mail.tm", "auth": "no API key; bearer token after mailbox creation", "steps": []}
|
||||
st, domains, ms = request("GET", base + "/domains")
|
||||
report["steps"].append({"step": "domains", "status": st, "ms": ms, "sample": redact(domains)})
|
||||
if not lifecycle or st != 200:
|
||||
return report
|
||||
acct_id = None
|
||||
token = None
|
||||
try:
|
||||
domain = domain_from(domains)
|
||||
address = "hermes-probe-" + "".join(secrets.choice(string.ascii_lowercase + string.digits) for _ in range(12)) + "@" + domain
|
||||
password = "P-" + secrets.token_urlsafe(18)
|
||||
st, acct, ms = request("POST", base + "/accounts", data={"address": address, "password": password})
|
||||
acct_id = acct.get("id") if isinstance(acct, dict) else None
|
||||
report["steps"].append({"step": "create_account", "status": st, "ms": ms, "address": address, "account_id": acct_id})
|
||||
st, tok, ms = request("POST", base + "/token", data={"address": address, "password": password})
|
||||
token = [REDACTED]"token") if isinstance(tok, dict) else None
|
||||
report["steps"].append({"step": "get_token", "status": st, "ms": ms, "token": mask(token or ""), "token_len": len(token or "")})
|
||||
st, me, ms = request("GET", base + "/me", headers={"Authorization": "Bearer " + token})
|
||||
report["steps"].append({"step": "me", "status": st, "ms": ms, "id_matches": isinstance(me, dict) and me.get("id") == acct_id})
|
||||
finally:
|
||||
if acct_id and token:
|
||||
st, body, ms = request("DELETE", base + f"/accounts/{acct_id}", headers={"Authorization": "Bearer " + token})
|
||||
report["steps"].append({"step": "delete_account", "status": st, "ms": ms, "deleted": st in (200, 202, 204)})
|
||||
return report
|
||||
|
||||
|
||||
def probe_webshare() -> Dict[str, Any]:
|
||||
token = [REDACTED]"WEBSHARE_TOKEN")
|
||||
report = {"provider": "webshare", "auth": "Authorization: Token <TOKEN>", "configured": bool(token), "steps": []}
|
||||
if not token:
|
||||
st, body, ms = request("GET", "https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page=1&page_size=1")
|
||||
report["steps"].append({"step": "no_auth_expected_401", "status": st, "ms": ms, "body": body})
|
||||
return report
|
||||
hdr = {"Authorization": "Token " + token}
|
||||
for step, url in [("profile", "https://proxy.webshare.io/api/v2/profile/"), ("proxy_list_one_page", "https://proxy.webshare.io/api/v2/proxy/list/?mode=direct&page=1&page_size=1")]:
|
||||
st, body, ms = request("GET", url, headers=hdr)
|
||||
report["steps"].append({"step": step, "status": st, "ms": ms, "body": redact(body)})
|
||||
return report
|
||||
|
||||
|
||||
def probe_mailsac() -> Dict[str, Any]:
|
||||
key = os.getenv("MAILSAC_KEY")
|
||||
report = {"provider": "mailsac", "auth": "Mailsac-Key header", "configured": bool(key), "steps": []}
|
||||
hdr = {"Mailsac-Key": key} if key else {}
|
||||
st, body, ms = request("GET", "https://mailsac.com/api/me", headers=hdr)
|
||||
report["steps"].append({"step": "me", "status": st, "ms": ms, "body": redact(body)})
|
||||
return report
|
||||
|
||||
|
||||
def probe_mailslurp() -> Dict[str, Any]:
|
||||
key = os.getenv("MAILSLURP_API_KEY")
|
||||
report = {"provider": "mailslurp", "auth": "x-api-key", "configured": bool(key), "steps": []}
|
||||
hdr = {"x-api-key": key} if key else {}
|
||||
st, body, ms = request("GET", "https://api.mailslurp.com/inboxes?size=1", headers=hdr)
|
||||
report["steps"].append({"step": "inboxes_page", "status": st, "ms": ms, "body": redact(body)})
|
||||
return report
|
||||
|
||||
|
||||
def probe_mailosaur() -> Dict[str, Any]:
|
||||
key = os.getenv("MAILOSAUR_API_KEY")
|
||||
report = {"provider": "mailosaur", "auth": "HTTP Basic", "configured": bool(key), "steps": []}
|
||||
if not key:
|
||||
st, body, ms = request("GET", "https://mailosaur.com/api/servers")
|
||||
report["steps"].append({"step": "servers_no_auth_expected_401", "status": st, "ms": ms, "body": body})
|
||||
return report
|
||||
for label, user, pwd in [("servers_key_as_username", key, ""), ("servers_api_colon_key", "api", key)]:
|
||||
basic = base64.b64encode(f"{user}:{pwd}".encode()).decode()
|
||||
st, body, ms = request("GET", "https://mailosaur.com/api/servers", headers={"Authorization": "Basic " + basic})
|
||||
report["steps"].append({"step": label, "status": st, "ms": ms, "body": redact(body)})
|
||||
if st < 400:
|
||||
break
|
||||
return report
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--mailtm-lifecycle", action="store_true", help="create one Mail.tm mailbox, get token, /me, then delete it")
|
||||
args = ap.parse_args()
|
||||
print(json.dumps({"generated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), "probes": [probe_mailtm(args.mailtm_lifecycle), probe_webshare(), probe_mailsac(), probe_mailslurp(), probe_mailosaur()]}, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
88
skills/free-tools-abuse/scripts/proxy_checker.py
Normal file
88
skills/free-tools-abuse/scripts/proxy_checker.py
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Proxy checker — проверяет список проксей на живость.
|
||||
Usage: python proxy_checker.py proxies.txt [--workers 20]
|
||||
"""
|
||||
import sys
|
||||
import requests
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
TEST_URL = "https://httpbin.org/ip"
|
||||
TIMEOUT = 8
|
||||
|
||||
def check_proxy(proxy_line: str) -> tuple[str, bool, str]:
|
||||
"""Check single proxy. Returns (proxy, is_alive, info)."""
|
||||
proxy_line = proxy_line.strip()
|
||||
if not proxy_line or proxy_line.startswith("#"):
|
||||
return (proxy_line, False, "skipped")
|
||||
|
||||
# Try http:// prefix if not present
|
||||
if "://" not in proxy_line:
|
||||
proxy_url = f"http://{proxy_line}"
|
||||
else:
|
||||
proxy_url = proxy_line
|
||||
|
||||
proxies = {"http": proxy_url, "https": proxy_url}
|
||||
|
||||
try:
|
||||
r = requests.get(TEST_URL, proxies=proxies, timeout=TIMEOUT)
|
||||
if r.status_code == 200:
|
||||
ip = r.json().get("origin", "unknown")
|
||||
return (proxy_line, True, ip)
|
||||
return (proxy_line, False, f"HTTP {r.status_code}")
|
||||
except requests.exceptions.ProxyError:
|
||||
return (proxy_line, False, "proxy error")
|
||||
except requests.exceptions.ConnectTimeout:
|
||||
return (proxy_line, False, "connect timeout")
|
||||
except requests.exceptions.ReadTimeout:
|
||||
return (proxy_line, False, "read timeout")
|
||||
except Exception as e:
|
||||
return (proxy_line, False, str(e)[:50])
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python proxy_checker.py <proxies.txt> [--workers 20]")
|
||||
sys.exit(1)
|
||||
|
||||
filepath = sys.argv[1]
|
||||
workers = 20
|
||||
if "--workers" in sys.argv:
|
||||
idx = sys.argv.index("--workers")
|
||||
workers = int(sys.argv[idx + 1])
|
||||
|
||||
with open(filepath, "r") as f:
|
||||
proxies = [line.strip() for line in f if line.strip()]
|
||||
|
||||
print(f"Checking {len(proxies)} proxies with {workers} workers...\n")
|
||||
|
||||
alive = []
|
||||
dead = 0
|
||||
|
||||
with ThreadPoolExecutor(max_workers=workers) as executor:
|
||||
futures = {executor.submit(check_proxy, p): p for p in proxies}
|
||||
for future in as_completed(futures):
|
||||
proxy, is_alive, info = future.result()
|
||||
if is_alive:
|
||||
alive.append(proxy)
|
||||
print(f" ✅ LIVE: {proxy} → {info}")
|
||||
else:
|
||||
dead += 1
|
||||
|
||||
print(f"\n--- Results ---")
|
||||
print(f"Total: {len(proxies)}")
|
||||
print(f"Alive: {len(alive)}")
|
||||
print(f"Dead: {dead}")
|
||||
|
||||
# Save alive proxies
|
||||
outfile = filepath.replace(".txt", "_alive.txt")
|
||||
if not outfile.endswith("_alive.txt"):
|
||||
outfile = filepath + "_alive.txt"
|
||||
|
||||
with open(outfile, "w") as f:
|
||||
f.write("\n".join(alive))
|
||||
print(f"Alive proxies saved to: {outfile}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
66
skills/free-tools-abuse/scripts/proxy_fetcher.py
Normal file
66
skills/free-tools-abuse/scripts/proxy_fetcher.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Pull fresh proxies from GitHub free lists.
|
||||
Sources: proxifly (every 5min), fyvri (hourly), vakhov (daily)
|
||||
|
||||
Usage: python proxy_fetcher.py [--output proxies.txt] [--check]
|
||||
"""
|
||||
import sys
|
||||
import requests
|
||||
|
||||
SOURCES = {
|
||||
"proxifly_http": "https://raw.githubusercontent.com/proxifly/free-proxy-list/main/proxies/protocols/http/data.txt",
|
||||
"proxifly_socks4": "https://raw.githubusercontent.com/proxifly/free-proxy-list/main/proxies/protocols/socks4/data.txt",
|
||||
"proxifly_socks5": "https://raw.githubusercontent.com/proxifly/free-proxy-list/main/proxies/protocols/socks5/data.txt",
|
||||
"fyvri": "https://raw.githubusercontent.com/fyvri/fresh-proxy-list/main/proxies.txt",
|
||||
"vakhov": "https://vakhov.github.io/fresh-proxy-list/proxies.txt",
|
||||
}
|
||||
|
||||
HEADERS = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
}
|
||||
|
||||
|
||||
def fetch_all():
|
||||
all_proxies = set()
|
||||
for name, url in SOURCES.items():
|
||||
try:
|
||||
r = requests.get(url, headers=HEADERS, timeout=15)
|
||||
if r.status_code == 200:
|
||||
proxies = [p.strip() for p in r.text.splitlines() if p.strip() and not p.startswith("#")]
|
||||
all_proxies.update(proxies)
|
||||
print(f" ✅ {name}: {len(proxies)} proxies")
|
||||
else:
|
||||
print(f" ❌ {name}: HTTP {r.status_code}")
|
||||
except Exception as e:
|
||||
print(f" ❌ {name}: {e}")
|
||||
return sorted(all_proxies)
|
||||
|
||||
|
||||
def main():
|
||||
outfile = "proxies.txt"
|
||||
do_check = False
|
||||
|
||||
args = sys.argv[1:]
|
||||
for i, arg in enumerate(args):
|
||||
if arg == "--output" and i + 1 < len(args):
|
||||
outfile = args[i + 1]
|
||||
elif arg == "--check":
|
||||
do_check = True
|
||||
|
||||
print(f"🔥 Fetching free proxies from {len(SOURCES)} sources...\n")
|
||||
proxies = fetch_all()
|
||||
|
||||
with open(outfile, "w") as f:
|
||||
f.write("\n".join(proxies))
|
||||
|
||||
print(f"\n📦 Total unique: {len(proxies)} → {outfile}")
|
||||
|
||||
if do_check:
|
||||
print(f"\n🔍 Running proxy checker...")
|
||||
import subprocess
|
||||
subprocess.run([sys.executable, "proxy_checker.py", outfile, "--workers", "30"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
162
skills/free-tools-abuse/scripts/registration_stack.py
Normal file
162
skills/free-tools-abuse/scripts/registration_stack.py
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Registration abuse stack — automated account creation pipeline.
|
||||
Uses: mail.tm (email) + receive-smss.com (SMS) + webshare.io (proxy)
|
||||
|
||||
Usage:
|
||||
python registration_stack.py --service google --count 5
|
||||
python registration_stack.py --service telegram --count 10 --proxy-list proxies.txt
|
||||
"""
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
MAILTM_API = "https://api.mail.tm"
|
||||
PROXY_LIST = [] # будет загружен из файла или webshare
|
||||
USER_AGENTS = [
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/[REDACTED-IP]",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/[REDACTED-IP]",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/[REDACTED-IP]",
|
||||
]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TEMP EMAIL (mail.tm)
|
||||
# ============================================================
|
||||
class TempEmail:
|
||||
def __init__(self):
|
||||
self.token = None
|
||||
self.address = None
|
||||
|
||||
def create(self):
|
||||
"""Create disposable email via mail.tm API."""
|
||||
# Get domains
|
||||
r = requests.get(f"{MAILTM_API}/domains")
|
||||
domain = r.json()["hydra:member"][0]["domain"]
|
||||
|
||||
# Random username
|
||||
username = f"user{random.randint(10000, 99999)}{int(time.time()) % 10000}"
|
||||
address = f"{username}@{domain}"
|
||||
|
||||
password = f"Pass{random.randint(1000, 9999)}!"
|
||||
r = requests.post(f"{MAILTM_API}/accounts", json={
|
||||
"address": address, "password": password
|
||||
})
|
||||
|
||||
if r.status_code == 201:
|
||||
self.token = [REDACTED])["token"]
|
||||
self.address = address
|
||||
print(f" 📧 Email: {address}")
|
||||
return address
|
||||
else:
|
||||
print(f" ❌ Email failed: {r.status_code} {r.text[:100]}")
|
||||
return None
|
||||
|
||||
def wait_for_code(self, timeout=60):
|
||||
"""Wait for verification code in inbox."""
|
||||
start = time.time()
|
||||
while time.time() - start < timeout:
|
||||
r = requests.get(f"{MAILTM_API}/messages",
|
||||
headers={"Authorization": f"Bearer {self.token}"})
|
||||
messages = r.json().get("hydra:member", [])
|
||||
|
||||
for msg in messages:
|
||||
# Get message body
|
||||
r2 = requests.get(f"{MAILTM_API}/messages/{msg['id']}",
|
||||
headers={"Authorization": f"Bearer {self.token}"})
|
||||
body = r2.json().get("text", "") or r2.json().get("html", "")
|
||||
|
||||
# Extract 6-digit code
|
||||
import re
|
||||
codes = re.findall(r'\b(\d{4,8})\b', body)
|
||||
if codes:
|
||||
print(f" ✅ Code found: {codes[0]}")
|
||||
return codes[0]
|
||||
|
||||
time.sleep(3)
|
||||
print(f" ⏰ Timeout waiting for code")
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PROXY
|
||||
# ============================================================
|
||||
def get_proxy():
|
||||
"""Get next proxy from rotation."""
|
||||
if not PROXY_LIST:
|
||||
return None
|
||||
return random.choice(PROXY_LIST)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TEMP SMS (receive-smss.com — web scraping)
|
||||
# ============================================================
|
||||
# NOTE: receive-smss.com doesn't have public API.
|
||||
# Use browser automation or fetch from their public page.
|
||||
# This is a placeholder — real implementation uses browser or paid API.
|
||||
class TempSMS:
|
||||
def __init__(self):
|
||||
self.numbers = []
|
||||
|
||||
def get_free_numbers(self):
|
||||
"""Scrape free numbers from receive-smss.com."""
|
||||
# Placeholder — use browser or web_extract
|
||||
print(" 📱 SMS: Use browser to get numbers from receive-smss.com")
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# MAIN
|
||||
# ============================================================
|
||||
def main():
|
||||
print("=" * 50)
|
||||
print(" Registration Abuse Stack")
|
||||
print("=" * 50)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python registration_stack.py --service <name> --count <N>")
|
||||
print("Services: google, telegram, twitter, instagram, whatsapp")
|
||||
sys.exit(1)
|
||||
|
||||
service = "telegram"
|
||||
count = 1
|
||||
|
||||
for i, arg in enumerate(sys.argv):
|
||||
if arg == "--service":
|
||||
service = sys.argv[i + 1]
|
||||
elif arg == "--count":
|
||||
count = int(sys.argv[i + 1])
|
||||
|
||||
print(f"\nTarget: {service} | Count: {count}\n")
|
||||
|
||||
for i in range(count):
|
||||
print(f"\n--- Account {i+1}/{count} ---")
|
||||
|
||||
# Step 1: Email
|
||||
email = TempEmail()
|
||||
email_addr = email.create()
|
||||
if not email_addr:
|
||||
continue
|
||||
|
||||
# Step 2: Proxy
|
||||
proxy = get_proxy()
|
||||
if proxy:
|
||||
print(f" 🌐 Proxy: {proxy}")
|
||||
|
||||
# Step 3: SMS (for Telegram)
|
||||
sms = TempSMS()
|
||||
sms.get_free_numbers()
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
print(f"\n✅ Done. {count} accounts prepared.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
49
skills/free-tools-abuse/scripts/tg_sms_bot_checker.py
Normal file
49
skills/free-tools-abuse/scripts/tg_sms_bot_checker.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# Telegram Temp SMS Bot Checker
|
||||
# Проверяет доступность бесплатных номеров в TG ботах
|
||||
|
||||
import sys
|
||||
import asyncio
|
||||
from telethon import TelegramClient
|
||||
from telethon.errors import SessionPasswordNeededError
|
||||
|
||||
# Конфиг — свои api_id/api_hash от my.telegram.org
|
||||
API_ID = 0 # FILL
|
||||
API_HASH = "" # FILL
|
||||
|
||||
BOTS = [
|
||||
"@ReceiveSMSRobot",
|
||||
"@SMSPVA_COM_BOT",
|
||||
]
|
||||
|
||||
async def check_bot(client, bot_username):
|
||||
"""Проверить, работает ли бот."""
|
||||
try:
|
||||
entity = await client.get_entity(bot_username)
|
||||
# Отправить /start
|
||||
await client.send_message(entity, "/start")
|
||||
await asyncio.sleep(2)
|
||||
# Получить ответ
|
||||
messages = await client.get_messages(entity, limit=3)
|
||||
for msg in messages:
|
||||
if msg.text:
|
||||
print(f" {bot_username}: {msg.text[:100]}")
|
||||
break
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f" ❌ {bot_username}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
client = TelegramClient("temp_sms_checker", API_ID, API_HASH)
|
||||
await client.start()
|
||||
print(f"✅ Logged in as: {(await client.get_me()).username}\n")
|
||||
|
||||
for bot in BOTS:
|
||||
await check_bot(client, bot)
|
||||
|
||||
await client.disconnect()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user