├── README.md ├── __init__.py ├── captcha ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-310.pyc │ ├── __init__.cpython-39.pyc │ ├── anycaptcha.cpython-310.pyc │ ├── anycaptcha.cpython-39.pyc │ ├── base.cpython-310.pyc │ └── base.cpython-39.pyc ├── anycaptcha.py └── base.py ├── config.ini ├── emailprovider ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-310.pyc │ ├── __init__.cpython-39.pyc │ ├── base.cpython-310.pyc │ ├── base.cpython-39.pyc │ ├── kopeechka.cpython-310.pyc │ └── kopeechka.cpython-39.pyc ├── base.py ├── hotmailbox.py └── kopeechka.py ├── mailinabox ├── __init__.py └── core.py ├── main.py ├── proxies.txt ├── requirements.txt ├── start.bat └── twitter ├── __init__.py ├── __pycache__ ├── __init__.cpython-310.pyc ├── __init__.cpython-39.pyc ├── core.cpython-310.pyc ├── core.cpython-39.pyc ├── eps.cpython-310.pyc ├── eps.cpython-39.pyc ├── exceptions.cpython-310.pyc ├── exceptions.cpython-39.pyc ├── models.cpython-310.pyc └── models.cpython-39.pyc ├── assets ├── banners │ └── D-jnKUPU4AE3hVR.jpg ├── bio.txt ├── locations.txt ├── names.txt ├── pfp │ └── pasted image 0.png ├── tweets.txt └── uas.txt ├── core.py ├── eps.py ├── exceptions.py └── models.py /README.md: -------------------------------------------------------------------------------- 1 | # Twitter-Token-Gen 2 | Twitter Token Generator, Multi-Thread, 200 tokens + per minute 3 | 4 | ![alt text](https://media1.tenor.com/images/8a36108783bfe1eb9e34f33dc624c6ce/tenor.gif?itemid=27343731) 5 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/__init__.py -------------------------------------------------------------------------------- /captcha/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__init__.py -------------------------------------------------------------------------------- /captcha/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /captcha/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /captcha/__pycache__/anycaptcha.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/anycaptcha.cpython-310.pyc -------------------------------------------------------------------------------- /captcha/__pycache__/anycaptcha.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/anycaptcha.cpython-39.pyc -------------------------------------------------------------------------------- /captcha/__pycache__/base.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/base.cpython-310.pyc -------------------------------------------------------------------------------- /captcha/__pycache__/base.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/captcha/__pycache__/base.cpython-39.pyc -------------------------------------------------------------------------------- /captcha/anycaptcha.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import typing as tp 3 | import time 4 | from .base import BaseCaptchaService, BaseTask, TaskType 5 | from .base import CaptchaErrorType, CaptchaException 6 | 7 | 8 | class AnyCaptchaService(BaseCaptchaService): 9 | _BASE_URL = "https://api.anycaptcha.com" 10 | _ERROR_ZERO_BALANCE = 1 11 | _STATUS_PROCESSING = "processing" 12 | _STATUS_READY = "ready" 13 | 14 | def __init__(self, api_key: str): 15 | super().__init__(api_key) 16 | self._BASE_PAYLOAD = {"clientKey": self._api_key} 17 | 18 | @staticmethod 19 | def _type_to_str(task_type: "TaskType") -> str: 20 | """ 21 | it converts TaskType object to its respective string. 22 | """ 23 | 24 | if task_type == TaskType.FUNCAPTCHA: 25 | return "FunCaptchaTaskProxyless" 26 | 27 | def _validate_response(self, response: "requests.models.Response") -> "tp.Dict": 28 | """ 29 | It basically validates the response content. 30 | 31 | Parameters: 32 | response (Response): a Response object. 33 | Returns: 34 | response's json content if exception is not raised. 35 | Raises: 36 | CaptchaException 37 | """ 38 | 39 | j = response.json() 40 | error_id = j["errorId"] 41 | 42 | if error_id != 0: # if error_id is different from 0 it means the request was invalid 43 | error_type = None 44 | if error_id == self._ERROR_ZERO_BALANCE: 45 | error_type = CaptchaErrorType.NO_BALANCE 46 | 47 | raise CaptchaException(j["errorDescription"], error_type) 48 | return j 49 | 50 | def get_balance(self) -> float: 51 | r = requests.post(self._BASE_URL + "/getBalance", json=self._BASE_PAYLOAD) 52 | return float(r.json()["balance"]) 53 | 54 | def create_task(self, task: "BaseTask"): 55 | r = requests.post( 56 | self._BASE_URL + "/createTask", 57 | json={ 58 | **self._BASE_PAYLOAD, 59 | "task": { 60 | "type": self._type_to_str(task.type), 61 | "websitePublicKey": task.public_key, 62 | "websiteUrl": task.page_url 63 | } 64 | } 65 | ) 66 | j = self._validate_response(r) 67 | return j["taskId"] 68 | 69 | def get_task_result(self, task_id: str, timeout: float) -> str: 70 | t0 = time.time() 71 | while time.time() - t0 < timeout: 72 | r = requests.post( 73 | self._BASE_URL + "/getTaskResult", 74 | json={ 75 | **self._BASE_PAYLOAD, 76 | "taskId": task_id 77 | } 78 | ) 79 | 80 | j = self._validate_response(r) 81 | if j["status"] == self._STATUS_PROCESSING: 82 | time.sleep(2) 83 | else: 84 | return j["solution"]["token"] # note that "token" works for funcaptcha only... 85 | 86 | raise TimeoutError 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /captcha/base.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from enum import Enum 3 | 4 | 5 | class CaptchaException(Exception): 6 | def __init__(self, message: str, error_type: "CaptchaErrorType"): 7 | super().__init__(message) 8 | self.error_type = error_type 9 | 10 | 11 | class CaptchaErrorType(Enum): 12 | NO_BALANCE = 1 13 | 14 | 15 | class TaskType(Enum): 16 | FUNCAPTCHA = 1 17 | 18 | 19 | class BaseTask(object): 20 | def __init__(self, _type: "TaskType", public_key: str, page_url: str): 21 | self.type = _type 22 | self.public_key = public_key 23 | self.page_url = page_url 24 | 25 | 26 | class BaseCaptchaService(object): 27 | def __init__(self, api_key: str): 28 | self._api_key = api_key 29 | 30 | @abstractmethod 31 | def get_balance(self): 32 | """ 33 | Get the account's balance. 34 | 35 | Returns: 36 | the account's balance. 37 | """ 38 | 39 | ... 40 | 41 | @abstractmethod 42 | def create_task(self, task: "BaseTask"): 43 | """ 44 | Initialize and create a captcha task. 45 | 46 | Parameters: 47 | task (BaseTask): a Task object. 48 | Returns: 49 | a task_id 50 | """ 51 | 52 | ... 53 | 54 | @abstractmethod 55 | def get_task_result(self, task_id: str, timeout: float): 56 | """ 57 | Get the captcha result. 58 | 59 | Parameters: 60 | task_id (str): task id got from create_task method 61 | timeout (float): max timeout to get result 62 | 63 | Returns: 64 | the captcha result. 65 | """ 66 | 67 | ... 68 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [app] 2 | hmb_apikey=8ede5a00f3f248f1b6d504c1b06d4075 3 | ks_apikey=293e752d412e634de2f8856941bdadd5 4 | anycap_apikey=07dcf4bec6c3414b988516d4f31d9686 5 | threads=100 6 | [run-settings] 7 | captcha_service=anycaptcha 8 | email_service=kopeechka 9 | -------------------------------------------------------------------------------- /emailprovider/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__init__.py -------------------------------------------------------------------------------- /emailprovider/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /emailprovider/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /emailprovider/__pycache__/base.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/base.cpython-310.pyc -------------------------------------------------------------------------------- /emailprovider/__pycache__/base.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/base.cpython-39.pyc -------------------------------------------------------------------------------- /emailprovider/__pycache__/kopeechka.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/kopeechka.cpython-310.pyc -------------------------------------------------------------------------------- /emailprovider/__pycache__/kopeechka.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/emailprovider/__pycache__/kopeechka.cpython-39.pyc -------------------------------------------------------------------------------- /emailprovider/base.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from enum import Enum 3 | import typing as tp 4 | 5 | 6 | class EmailException(Exception): 7 | def __init__(self, message: str, error_type: "EmailErrorType"): 8 | super().__init__(message) 9 | self.error_type = error_type 10 | 11 | 12 | class EmailErrorType(Enum): 13 | NO_BALANCE = 1 14 | CANNOT_FETCH_OTP = 2 15 | CANNOT_GET_EMAIL = 3 16 | NO_STOCK = 4 17 | 18 | 19 | class EmailResponse(object): 20 | def __init__(self, email: str, password: str, task_id: "tp.Optional[str]" = None): 21 | self.email = email 22 | self.password = password 23 | self.task_id = task_id 24 | 25 | 26 | class EmailMatch(object): 27 | def __init__(self, pattern: "tp.Optional[str]" = None, subject: "tp.Optional[str]" = None): 28 | self.pattern = pattern 29 | self.subject = subject.lower() if subject else subject 30 | 31 | 32 | class BaseEmailService(object): 33 | def __init__(self, api_key: str): 34 | self._api_key = api_key 35 | 36 | @abstractmethod 37 | def get_email(self) -> "EmailResponse": 38 | ... 39 | 40 | @abstractmethod 41 | def get_otp( 42 | self, 43 | email_response: "EmailResponse", 44 | email_match: "EmailMatch", 45 | timeout: float = 60.0 46 | ) -> str: 47 | ... 48 | 49 | @abstractmethod 50 | def balance(self) -> float: 51 | ... 52 | -------------------------------------------------------------------------------- /emailprovider/hotmailbox.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | import re 4 | import email 5 | import imaplib 6 | import typing as tp 7 | from .base import BaseEmailService, EmailResponse, EmailMatch 8 | from .base import EmailErrorType, EmailException 9 | 10 | 11 | class HotmailBoxService(BaseEmailService): 12 | _BASE_URL = "https://api.hotmailbox.me" 13 | 14 | def __init__(self, api_key: str): 15 | super().__init__(api_key) 16 | self._BASE_PAYLOAD = {"apikey": self._api_key} 17 | 18 | def _validate_response(self, response: "requests.models.Response") -> "tp.Dict": 19 | j = response.json() 20 | if not ("Data" in j): 21 | raise EmailException("Unknown Error", EmailErrorType.CANNOT_GET_EMAIL) 22 | return j 23 | 24 | def get_email(self) -> "EmailResponse": 25 | r = requests.get( 26 | self._BASE_URL + "/mail/buy", 27 | params={ 28 | "mailcode": "HOTMAIL", 29 | "quantity": 1 30 | } 31 | ) 32 | j = self._validate_response(r) 33 | return EmailResponse(j["data"]["Emails"][0]["Email"], j["data"]["Emails"][0]["Password"]) 34 | 35 | def get_otp( 36 | self, 37 | email_response: "EmailResponse", 38 | email_match: "EmailMatch", 39 | timeout: float = 60.0 40 | ) -> str: 41 | try: 42 | imap = imaplib.IMAP4_SSL("outlook.office365.com", 993) 43 | 44 | t0 = time.time() 45 | while time.time() - t0 < timeout: 46 | data = imap.search(None, "(UNSEEN)")[1] 47 | for num in data[0].split(): 48 | data = imap.fetch(num, "(RFC822)")[1] 49 | email_object = email.message_from_bytes(data[0][1]) 50 | 51 | if email_match.subject in email_object["subject"].lower(): 52 | for part in email_object.walk(): 53 | if part.get_content_type() == "text/plain": 54 | part = part.get_payload(None, True) 55 | found = re.search(email_match.pattern, part.decode()) 56 | if found is not None: 57 | return found.group() 58 | except imap.error: 59 | raise EmailException("Imap Error", EmailErrorType.CANNOT_FETCH_OTP) 60 | else: 61 | raise TimeoutError # if function has not returned yet and no error raised before 62 | -------------------------------------------------------------------------------- /emailprovider/kopeechka.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import uuid 3 | import time 4 | import typing as tp 5 | from .base import BaseEmailService, EmailResponse, EmailMatch 6 | from .base import EmailException, EmailErrorType 7 | 8 | 9 | class KopeechkaService(BaseEmailService): 10 | _BASE_URL = "http://api.kopeechka.store" 11 | _WAIT_STATUS = "WAIT_LINK" 12 | _NO_BALANCE_ERROR = "BAD_BALANCE" 13 | 14 | def __init__(self, api_key: str): 15 | super().__init__(api_key) 16 | self._BASE_PAYLOAD = {"token": self._api_key, "api": "2.0"} 17 | 18 | def _validate_response(self, response: "requests.models.Response") -> "tp.Dict": 19 | j = response.json() 20 | 21 | if j["status"] == "ERROR": 22 | error_type = None 23 | 24 | value = j.get("value") 25 | if value == self._NO_BALANCE_ERROR: 26 | error_type = EmailErrorType.NO_BALANCE 27 | 28 | raise EmailException("", error_type) 29 | 30 | return j 31 | 32 | def get_email(self) -> "EmailResponse": 33 | r = requests.get( 34 | self._BASE_URL + "/mailbox-get-email", 35 | params={ 36 | "site": "https://twitter.com/i/flow/signup", 37 | "mail_type": "OUTLOOK", 38 | "clear": "1", 39 | **self._BASE_PAYLOAD, 40 | } 41 | ) 42 | j = self._validate_response(r) 43 | password = str(uuid.uuid4()).replace("-", "")[:12] 44 | return EmailResponse(j["mail"], password, j["id"]) 45 | 46 | def get_otp( 47 | self, 48 | email_response: "EmailResponse", 49 | email_match: "EmailMatch", 50 | timeout: float = 60.0 51 | ) -> str: 52 | t0 = time.time() 53 | while time.time() - t0 < timeout: 54 | r = requests.get( 55 | self._BASE_URL + "/mailbox-get-message", 56 | params={"id": email_response.task_id, **self._BASE_PAYLOAD} 57 | ) 58 | j = r.json() 59 | if j["value"] == self._WAIT_STATUS: 60 | time.sleep(2) 61 | else: 62 | return j["value"] 63 | 64 | raise EmailException("TimeoutError", EmailErrorType.CANNOT_FETCH_OTP) 65 | 66 | def get_balance(self) -> float: 67 | r = requests.get( 68 | self._BASE_URL + "/user-balance", 69 | params=self._BASE_PAYLOAD 70 | ) 71 | 72 | return float(r.json()["balance"]) 73 | -------------------------------------------------------------------------------- /mailinabox/__init__.py: -------------------------------------------------------------------------------- 1 | from . import core -------------------------------------------------------------------------------- /mailinabox/core.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import base64 3 | import uuid 4 | import imaplib 5 | import email 6 | import time 7 | import re 8 | import typing as tp 9 | 10 | import urllib3 11 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 12 | 13 | 14 | class MailInABox(object): 15 | def __init__(self, username: str, password: str, hostname: str): 16 | """ 17 | Parameters: 18 | username (str): the admin's username (E.g: admin@example.com) 19 | password (str): the admin's password 20 | hostname (str): full hostname (E.g: box.example.com) 21 | """ 22 | 23 | self._auth_token = base64.urlsafe_b64encode(f"{username}:{password}".encode()).decode() 24 | self._basic_url = f"https://{hostname}/admin" 25 | self._hostname = hostname 26 | 27 | @staticmethod 28 | def _get_random_string(length: int) -> str: 29 | return str(uuid.uuid4()).replace("-", "")[:length] 30 | 31 | def get_email(self, domain: str) -> "tp.Tuple[str, str]": 32 | email, password = self._get_random_string(16), self._get_random_string(12) 33 | email += f"@{domain}" 34 | 35 | requests.post( 36 | self._basic_url + "/mail/users/add", 37 | verify=False, 38 | headers={"authorization": f"Basic {self._auth_token}"}, 39 | data={ 40 | "email": email, 41 | "password": password, 42 | "privileges": "" 43 | } 44 | ) 45 | 46 | return email, password 47 | 48 | def delete_email(self, email: str): 49 | requests.post( 50 | self._basic_url + "/mail/users/remove", 51 | verify=False, 52 | headers={"authorization": f"Basic {self._auth_token}"}, 53 | data={"email": email} 54 | ) 55 | 56 | def get_mailbox( 57 | self, 58 | subject_match: str, 59 | pattern: "tp.Union[tp.Pattern, str]", 60 | email_address: str, 61 | password: str, 62 | timeout: float = 60.0 63 | ) -> str: 64 | imap = imaplib.IMAP4_SSL(self._hostname, 993) 65 | imap.login(email_address, password) 66 | imap.select("Inbox") 67 | 68 | t0 = time.time() 69 | while time.time() - t0 < timeout: 70 | data = imap.search(None, "(UNSEEN)")[1] 71 | for num in data[0].split(): 72 | data = imap.fetch(num, "(RFC822)")[1] 73 | em = email.message_from_bytes(data[0][1]) 74 | 75 | if subject_match.lower() in em["subject"].lower(): 76 | for part in em.walk(): 77 | if part.get_content_type() == "text/plain": 78 | part = part.get_payload(None, True) 79 | found = re.search(pattern, part.decode()) 80 | if found is not None: 81 | return found.group() 82 | 83 | raise TimeoutError("timeout of %.2f seconds exceeded" % timeout) 84 | 85 | 86 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from emailprovider.kopeechka import KopeechkaService 3 | from emailprovider.base import EmailException, EmailErrorType, EmailMatch 4 | from captcha.anycaptcha import AnyCaptchaService 5 | from captcha.base import BaseTask, TaskType, CaptchaException, CaptchaErrorType 6 | from twitter.exceptions import InvalidEmail, FailedToCreate, BadProxy 7 | from twitter.core import TwitterAccount 8 | from twitter.models import Proxy 9 | from configparser import ConfigParser 10 | from threading import Lock, Event 11 | from concurrent.futures import ThreadPoolExecutor, as_completed 12 | from os import path 13 | 14 | import requests 15 | import random 16 | import re 17 | import typing as tp 18 | 19 | 20 | PKG_PATH = path.abspath(path.dirname(__file__)) 21 | 22 | cfg = ConfigParser() 23 | cfg.read(path.sep.join([PKG_PATH, "config.ini"])) 24 | HMB_APIKEY = cfg.get("app", "hmb_apikey") 25 | ANYCAP_APIKEY = cfg.get("app", "anycap_apikey") 26 | KS_APIKEY = cfg.get("app", "ks_apikey") 27 | THREADS = cfg.getint("app", "threads") 28 | CAPTCHA_SERVICE = cfg.get("run-settings", "captcha_service").lower() 29 | EMAIL_SERVICE = cfg.get("run-settings", "email_service").lower() 30 | AVAILABLE_CAPTCHA_SERVICES = ["anycaptcha"] 31 | AVAILABLE_EMAIL_SERVICES = ["kopeechka", "hotmailbox"] 32 | 33 | 34 | class Main(object): 35 | def __init__(self,): 36 | self._ks = KopeechkaService(KS_APIKEY) 37 | self._cap = AnyCaptchaService(ANYCAP_APIKEY) 38 | self._cap_task = BaseTask(TaskType.FUNCAPTCHA, "2CB16598-CB82-4CF7-B332-5990DB66F3AB", "https://twitter.com/i/flow/signup") 39 | self._threads = THREADS 40 | self._lock = Lock() 41 | self._event = Event() 42 | self._jobs = 500 43 | self._proxies: "tp.List[Proxy]" = list() 44 | self._counter = 0 45 | 46 | def _load_proxies(self): 47 | with open(path.sep.join([PKG_PATH, "proxies.txt"])) as fp: 48 | for proxy in fp.read().split("\n"): 49 | user, pswd, host, port = re.search(r"(.+):(.+)@(.+):(.+)", proxy.strip()).groups() 50 | self._proxies.append(Proxy(user, pswd, host, port)) 51 | 52 | def _remove_proxy(self, proxy: "Proxy"): 53 | with self._lock: 54 | if proxy in self._proxies: 55 | self._proxies.remove(proxy) 56 | 57 | def _get_proxy(self) -> "Proxy": 58 | with self._lock: 59 | if len(self._proxies) > 0: 60 | return random.choice(self._proxies) 61 | 62 | self._event.set() 63 | print("[*] Exiting because proxy balance is not enough.") 64 | 65 | @staticmethod 66 | def _append_success_file(line: str): 67 | file_path = path.sep.join([PKG_PATH, "twitter.txt"]) 68 | with open(file_path, "a") as fp: 69 | fp.write(line + "\n") 70 | 71 | def _handle_captcha_exception(self, exception: "CaptchaException"): 72 | if exception.error_type == CaptchaErrorType.NO_BALANCE: 73 | self._event.set() 74 | print("[*] Exiting because captcha balance is not enough.") 75 | 76 | def _handle_email_exception(self, exception: "EmailException"): 77 | if exception.error_type == EmailErrorType.NO_BALANCE: 78 | self._event.set() 79 | print("[*] Exiting because email balance is not enough.") 80 | 81 | def _worker(self): 82 | if not self._event.is_set(): 83 | done = False 84 | proxy = self._get_proxy() 85 | 86 | try: 87 | email = self._ks.get_email() 88 | while not self._event.is_set() and not done: 89 | try: 90 | tw = TwitterAccount(email.email, email.password, proxy) 91 | tw.name += f"{random.randint(100, 500)}.{random.choice(['eth', 'sol'])}" 92 | tw.init() 93 | 94 | captcha = self._cap.get_task_result(self._cap.create_task(self._cap_task), 100.0) 95 | print("[*] Captcha fetched successfully: %s..." % captcha[:18]) 96 | code = self._ks.get_otp(email, EmailMatch(r"\s(\d{6})\s"), 120.0) 97 | 98 | tw.submit_verification_code(code, captcha) 99 | tw.finalize() 100 | 101 | self._append_success_file(f"{tw.username}:{email.password}:{email.email}:{tw.get_auth_token()}") 102 | print("[*] New: %s" % tw.username) 103 | 104 | with self._lock: 105 | self._counter += 1 106 | print("[*] Counter is at: %d" % self._counter) 107 | done = True 108 | 109 | except CaptchaException as exception: 110 | self._handle_captcha_exception(exception) 111 | 112 | except (InvalidEmail, FailedToCreate): 113 | done = True 114 | 115 | except (BadProxy, requests.exceptions.ProxyError, requests.exceptions.ConnectionError): 116 | self._remove_proxy(proxy) 117 | proxy = self._get_proxy() 118 | 119 | except EmailException as exception: 120 | self._handle_email_exception(exception) 121 | 122 | def run(self): 123 | self._load_proxies() 124 | 125 | jobs = [] 126 | 127 | while ( 128 | not self._event.is_set() and 129 | self._ks.get_balance() > 0 and 130 | self._cap.get_balance() > 0 131 | ): 132 | with ThreadPoolExecutor(self._threads) as executor: 133 | for _ in range(self._jobs): 134 | job = executor.submit(self._worker) 135 | jobs.append(job) 136 | 137 | for job in as_completed(jobs): 138 | job.result() 139 | 140 | jobs.clear() 141 | 142 | 143 | if __name__ == "__main__": 144 | main = Main() 145 | 146 | if ( 147 | not (CAPTCHA_SERVICE in AVAILABLE_CAPTCHA_SERVICES) or 148 | not (EMAIL_SERVICE in AVAILABLE_EMAIL_SERVICES) 149 | ): 150 | print("[*] Something went wrong, cannot start with these settings... please check config.ini file.") 151 | else: 152 | main.run() 153 | -------------------------------------------------------------------------------- /proxies.txt: -------------------------------------------------------------------------------- 1 | JzigwiOkV6-cc-us-sid-86794704:LtWfhct4@gw.proxy.rainproxy.io:5959 2 | JzigwiOkV6-cc-us-sid-77254830:LtWfhct4@gw.proxy.rainproxy.io:5959 3 | JzigwiOkV6-cc-us-sid-53211055:LtWfhct4@gw.proxy.rainproxy.io:5959 4 | JzigwiOkV6-cc-us-sid-96035141:LtWfhct4@gw.proxy.rainproxy.io:5959 5 | JzigwiOkV6-cc-us-sid-43748646:LtWfhct4@gw.proxy.rainproxy.io:5959 6 | JzigwiOkV6-cc-us-sid-80036231:LtWfhct4@gw.proxy.rainproxy.io:5959 7 | JzigwiOkV6-cc-us-sid-22196365:LtWfhct4@gw.proxy.rainproxy.io:5959 8 | JzigwiOkV6-cc-us-sid-47121828:LtWfhct4@gw.proxy.rainproxy.io:5959 9 | JzigwiOkV6-cc-us-sid-42044103:LtWfhct4@gw.proxy.rainproxy.io:5959 10 | JzigwiOkV6-cc-us-sid-67958779:LtWfhct4@gw.proxy.rainproxy.io:5959 11 | JzigwiOkV6-cc-us-sid-47057399:LtWfhct4@gw.proxy.rainproxy.io:5959 12 | JzigwiOkV6-cc-us-sid-14794722:LtWfhct4@gw.proxy.rainproxy.io:5959 13 | JzigwiOkV6-cc-us-sid-37870587:LtWfhct4@gw.proxy.rainproxy.io:5959 14 | JzigwiOkV6-cc-us-sid-59123419:LtWfhct4@gw.proxy.rainproxy.io:5959 15 | JzigwiOkV6-cc-us-sid-97736856:LtWfhct4@gw.proxy.rainproxy.io:5959 16 | JzigwiOkV6-cc-us-sid-90750765:LtWfhct4@gw.proxy.rainproxy.io:5959 17 | JzigwiOkV6-cc-us-sid-55411459:LtWfhct4@gw.proxy.rainproxy.io:5959 18 | JzigwiOkV6-cc-us-sid-21742697:LtWfhct4@gw.proxy.rainproxy.io:5959 19 | JzigwiOkV6-cc-us-sid-81672906:LtWfhct4@gw.proxy.rainproxy.io:5959 20 | JzigwiOkV6-cc-us-sid-92846626:LtWfhct4@gw.proxy.rainproxy.io:5959 21 | JzigwiOkV6-cc-us-sid-13837444:LtWfhct4@gw.proxy.rainproxy.io:5959 22 | JzigwiOkV6-cc-us-sid-58898921:LtWfhct4@gw.proxy.rainproxy.io:5959 23 | JzigwiOkV6-cc-us-sid-15352820:LtWfhct4@gw.proxy.rainproxy.io:5959 24 | JzigwiOkV6-cc-us-sid-29238890:LtWfhct4@gw.proxy.rainproxy.io:5959 25 | JzigwiOkV6-cc-us-sid-39037563:LtWfhct4@gw.proxy.rainproxy.io:5959 26 | JzigwiOkV6-cc-us-sid-13202705:LtWfhct4@gw.proxy.rainproxy.io:5959 27 | JzigwiOkV6-cc-us-sid-94081119:LtWfhct4@gw.proxy.rainproxy.io:5959 28 | JzigwiOkV6-cc-us-sid-46216333:LtWfhct4@gw.proxy.rainproxy.io:5959 29 | JzigwiOkV6-cc-us-sid-75757047:LtWfhct4@gw.proxy.rainproxy.io:5959 30 | JzigwiOkV6-cc-us-sid-68284709:LtWfhct4@gw.proxy.rainproxy.io:5959 31 | JzigwiOkV6-cc-us-sid-89955705:LtWfhct4@gw.proxy.rainproxy.io:5959 32 | JzigwiOkV6-cc-us-sid-64933704:LtWfhct4@gw.proxy.rainproxy.io:5959 33 | JzigwiOkV6-cc-us-sid-98926794:LtWfhct4@gw.proxy.rainproxy.io:5959 34 | JzigwiOkV6-cc-us-sid-90098740:LtWfhct4@gw.proxy.rainproxy.io:5959 35 | JzigwiOkV6-cc-us-sid-56596863:LtWfhct4@gw.proxy.rainproxy.io:5959 36 | JzigwiOkV6-cc-us-sid-48919815:LtWfhct4@gw.proxy.rainproxy.io:5959 37 | JzigwiOkV6-cc-us-sid-73751405:LtWfhct4@gw.proxy.rainproxy.io:5959 38 | JzigwiOkV6-cc-us-sid-78261973:LtWfhct4@gw.proxy.rainproxy.io:5959 39 | JzigwiOkV6-cc-us-sid-36065776:LtWfhct4@gw.proxy.rainproxy.io:5959 40 | JzigwiOkV6-cc-us-sid-31034608:LtWfhct4@gw.proxy.rainproxy.io:5959 41 | JzigwiOkV6-cc-us-sid-48903082:LtWfhct4@gw.proxy.rainproxy.io:5959 42 | JzigwiOkV6-cc-us-sid-75988947:LtWfhct4@gw.proxy.rainproxy.io:5959 43 | JzigwiOkV6-cc-us-sid-53564608:LtWfhct4@gw.proxy.rainproxy.io:5959 44 | JzigwiOkV6-cc-us-sid-26090383:LtWfhct4@gw.proxy.rainproxy.io:5959 45 | JzigwiOkV6-cc-us-sid-16802946:LtWfhct4@gw.proxy.rainproxy.io:5959 46 | JzigwiOkV6-cc-us-sid-99321616:LtWfhct4@gw.proxy.rainproxy.io:5959 47 | JzigwiOkV6-cc-us-sid-23086234:LtWfhct4@gw.proxy.rainproxy.io:5959 48 | JzigwiOkV6-cc-us-sid-78323935:LtWfhct4@gw.proxy.rainproxy.io:5959 49 | JzigwiOkV6-cc-us-sid-53493866:LtWfhct4@gw.proxy.rainproxy.io:5959 50 | JzigwiOkV6-cc-us-sid-85678548:LtWfhct4@gw.proxy.rainproxy.io:5959 51 | JzigwiOkV6-cc-us-sid-32831079:LtWfhct4@gw.proxy.rainproxy.io:5959 52 | JzigwiOkV6-cc-us-sid-38270287:LtWfhct4@gw.proxy.rainproxy.io:5959 53 | JzigwiOkV6-cc-us-sid-14306199:LtWfhct4@gw.proxy.rainproxy.io:5959 54 | JzigwiOkV6-cc-us-sid-55480869:LtWfhct4@gw.proxy.rainproxy.io:5959 55 | JzigwiOkV6-cc-us-sid-27582652:LtWfhct4@gw.proxy.rainproxy.io:5959 56 | JzigwiOkV6-cc-us-sid-34119030:LtWfhct4@gw.proxy.rainproxy.io:5959 57 | JzigwiOkV6-cc-us-sid-49802669:LtWfhct4@gw.proxy.rainproxy.io:5959 58 | JzigwiOkV6-cc-us-sid-82356386:LtWfhct4@gw.proxy.rainproxy.io:5959 59 | JzigwiOkV6-cc-us-sid-94608233:LtWfhct4@gw.proxy.rainproxy.io:5959 60 | JzigwiOkV6-cc-us-sid-62552233:LtWfhct4@gw.proxy.rainproxy.io:5959 61 | JzigwiOkV6-cc-us-sid-17168659:LtWfhct4@gw.proxy.rainproxy.io:5959 62 | JzigwiOkV6-cc-us-sid-61649634:LtWfhct4@gw.proxy.rainproxy.io:5959 63 | JzigwiOkV6-cc-us-sid-55335829:LtWfhct4@gw.proxy.rainproxy.io:5959 64 | JzigwiOkV6-cc-us-sid-80201707:LtWfhct4@gw.proxy.rainproxy.io:5959 65 | JzigwiOkV6-cc-us-sid-25649393:LtWfhct4@gw.proxy.rainproxy.io:5959 66 | JzigwiOkV6-cc-us-sid-34417819:LtWfhct4@gw.proxy.rainproxy.io:5959 67 | JzigwiOkV6-cc-us-sid-14096110:LtWfhct4@gw.proxy.rainproxy.io:5959 68 | JzigwiOkV6-cc-us-sid-23319594:LtWfhct4@gw.proxy.rainproxy.io:5959 69 | JzigwiOkV6-cc-us-sid-97004185:LtWfhct4@gw.proxy.rainproxy.io:5959 70 | JzigwiOkV6-cc-us-sid-52830434:LtWfhct4@gw.proxy.rainproxy.io:5959 71 | JzigwiOkV6-cc-us-sid-39524127:LtWfhct4@gw.proxy.rainproxy.io:5959 72 | JzigwiOkV6-cc-us-sid-60061330:LtWfhct4@gw.proxy.rainproxy.io:5959 73 | JzigwiOkV6-cc-us-sid-19977471:LtWfhct4@gw.proxy.rainproxy.io:5959 74 | JzigwiOkV6-cc-us-sid-20337581:LtWfhct4@gw.proxy.rainproxy.io:5959 75 | JzigwiOkV6-cc-us-sid-89077303:LtWfhct4@gw.proxy.rainproxy.io:5959 76 | JzigwiOkV6-cc-us-sid-20066370:LtWfhct4@gw.proxy.rainproxy.io:5959 77 | JzigwiOkV6-cc-us-sid-48047672:LtWfhct4@gw.proxy.rainproxy.io:5959 78 | JzigwiOkV6-cc-us-sid-96737038:LtWfhct4@gw.proxy.rainproxy.io:5959 79 | JzigwiOkV6-cc-us-sid-88919856:LtWfhct4@gw.proxy.rainproxy.io:5959 80 | JzigwiOkV6-cc-us-sid-71628480:LtWfhct4@gw.proxy.rainproxy.io:5959 81 | JzigwiOkV6-cc-us-sid-58992652:LtWfhct4@gw.proxy.rainproxy.io:5959 82 | JzigwiOkV6-cc-us-sid-21156086:LtWfhct4@gw.proxy.rainproxy.io:5959 83 | JzigwiOkV6-cc-us-sid-88831307:LtWfhct4@gw.proxy.rainproxy.io:5959 84 | JzigwiOkV6-cc-us-sid-67528477:LtWfhct4@gw.proxy.rainproxy.io:5959 85 | JzigwiOkV6-cc-us-sid-58439441:LtWfhct4@gw.proxy.rainproxy.io:5959 86 | JzigwiOkV6-cc-us-sid-52210514:LtWfhct4@gw.proxy.rainproxy.io:5959 87 | JzigwiOkV6-cc-us-sid-52254593:LtWfhct4@gw.proxy.rainproxy.io:5959 88 | JzigwiOkV6-cc-us-sid-31743415:LtWfhct4@gw.proxy.rainproxy.io:5959 89 | JzigwiOkV6-cc-us-sid-65031460:LtWfhct4@gw.proxy.rainproxy.io:5959 90 | JzigwiOkV6-cc-us-sid-74175385:LtWfhct4@gw.proxy.rainproxy.io:5959 91 | JzigwiOkV6-cc-us-sid-15587084:LtWfhct4@gw.proxy.rainproxy.io:5959 92 | JzigwiOkV6-cc-us-sid-90146823:LtWfhct4@gw.proxy.rainproxy.io:5959 93 | JzigwiOkV6-cc-us-sid-95826128:LtWfhct4@gw.proxy.rainproxy.io:5959 94 | JzigwiOkV6-cc-us-sid-67291577:LtWfhct4@gw.proxy.rainproxy.io:5959 95 | JzigwiOkV6-cc-us-sid-99907861:LtWfhct4@gw.proxy.rainproxy.io:5959 96 | JzigwiOkV6-cc-us-sid-71230208:LtWfhct4@gw.proxy.rainproxy.io:5959 97 | JzigwiOkV6-cc-us-sid-80193068:LtWfhct4@gw.proxy.rainproxy.io:5959 98 | JzigwiOkV6-cc-us-sid-60242067:LtWfhct4@gw.proxy.rainproxy.io:5959 99 | JzigwiOkV6-cc-us-sid-19661460:LtWfhct4@gw.proxy.rainproxy.io:5959 100 | JzigwiOkV6-cc-us-sid-29969032:LtWfhct4@gw.proxy.rainproxy.io:5959 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aio5 2 | certifi==2022.9.24 3 | charset-normalizer==2.1.1 4 | idna==3.4 5 | requests==2.28.1 6 | six==1.16.0 7 | urllib3==1.26.13 8 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | pip install -r requirements.txt 2 | python main.py 3 | pause -------------------------------------------------------------------------------- /twitter/__init__.py: -------------------------------------------------------------------------------- 1 | from . import core -------------------------------------------------------------------------------- /twitter/__pycache__/__init__.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/__init__.cpython-310.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/core.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/core.cpython-310.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/core.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/core.cpython-39.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/eps.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/eps.cpython-310.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/eps.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/eps.cpython-39.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/exceptions.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/exceptions.cpython-310.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/exceptions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/exceptions.cpython-39.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/models.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/models.cpython-310.pyc -------------------------------------------------------------------------------- /twitter/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /twitter/assets/banners/D-jnKUPU4AE3hVR.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/assets/banners/D-jnKUPU4AE3hVR.jpg -------------------------------------------------------------------------------- /twitter/assets/bio.txt: -------------------------------------------------------------------------------- 1 | by gen -------------------------------------------------------------------------------- /twitter/assets/locations.txt: -------------------------------------------------------------------------------- 1 | australia -------------------------------------------------------------------------------- /twitter/assets/names.txt: -------------------------------------------------------------------------------- 1 | randomnftne -------------------------------------------------------------------------------- /twitter/assets/pfp/pasted image 0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1xmr/Twitter-Token-Gen/b04958dc7bb86537db4a1d9da9b1bff12ac18d25/twitter/assets/pfp/pasted image 0.png -------------------------------------------------------------------------------- /twitter/assets/tweets.txt: -------------------------------------------------------------------------------- 1 | drained by metamask blabla some dumb shit 150 lines just drained by metamask blabla some dumb shit 150 lines just drained by metamask blabla some dumb shit 150 lines just -------------------------------------------------------------------------------- /twitter/assets/uas.txt: -------------------------------------------------------------------------------- 1 | newyork -------------------------------------------------------------------------------- /twitter/core.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import uuid 3 | import os 4 | import random 5 | import typing as tp 6 | from .eps import * 7 | from . import models 8 | from . import exceptions 9 | 10 | 11 | _PKG_DIR = os.path.abspath(os.path.dirname(__file__)) 12 | _ASSETS_DIR = os.path.sep.join([_PKG_DIR, "assets"]) 13 | 14 | 15 | class TwitterAccount(object): 16 | _HEADERS = { 17 | "cache-control": "no-store", 18 | "accept-encoding": "gzip, deflate", 19 | "x-twitter-active-user": "yes", 20 | "accept": "application/json", 21 | "authorization": TWITTER_AUTHORIZATION_HEADER, 22 | "x-twitter-client-language": "en" 23 | } 24 | 25 | def __init__(self, email: str, password: str, proxy: "models.Proxy"): 26 | """ 27 | Set and load initial attributes. 28 | 29 | Parameters: 30 | email (str): the account's email you want to use 31 | password (str): the account's password you want to use 32 | proxy (Proxy): a Proxy object 33 | """ 34 | 35 | # load all the assets 36 | self._banners = os.listdir(os.path.sep.join([_ASSETS_DIR, "banners"])) 37 | self._pfps = os.listdir(os.path.sep.join([_ASSETS_DIR, "pfp"])) 38 | self._tweets = self._get_file_lines(os.path.sep.join([_ASSETS_DIR, "tweets.txt"])) 39 | self._bios = self._get_file_lines(os.path.sep.join([_ASSETS_DIR, "bio.txt"])) 40 | self._locations = self._get_file_lines(os.path.sep.join([_ASSETS_DIR, "locations.txt"])) 41 | self._names = self._get_file_lines(os.path.sep.join([_ASSETS_DIR, "names.txt"])) 42 | self._uas = self._get_file_lines(os.path.sep.join([_ASSETS_DIR, "uas.txt"])) 43 | self._flow_token = "" 44 | 45 | self.session = requests.Session() 46 | self.session.headers.update(self._HEADERS) 47 | 48 | self.session.headers["user-agent"] = random.choice(self._uas) 49 | self.session.headers["x-csrf-token"] = str(uuid.uuid4()).replace("-", "") 50 | self.session.cookies.set("ct0", self.session.headers["x-csrf-token"]) 51 | 52 | self.session.proxies.update({"http": str(proxy), "https": str(proxy)}) 53 | 54 | self.username = "" 55 | self.name = random.choice(self._names) 56 | self.email = email 57 | self.password = password 58 | 59 | @staticmethod 60 | def _validate_task_response(response: "tp.Dict", exception: "tp.Any", where): 61 | """ 62 | Raises an exception if "errors" is contained in response. 63 | 64 | Parameters: 65 | response (Dict): response's json from task request "r.json()" 66 | exception (Any): exception that you want to raise if response contains 67 | Raises: 68 | exception 69 | """ 70 | 71 | if "errors" in response: 72 | print(response) 73 | print(where) 74 | raise exception 75 | 76 | @staticmethod 77 | def _get_file_lines(file_path: str) -> "tp.List[str]": 78 | """ 79 | Get lines from file. 80 | 81 | Parameters: 82 | file_path (str): path of the file you want to retrieve lines from 83 | Returns: 84 | list of lines 85 | """ 86 | 87 | lines = [] 88 | with open(file_path) as fp: 89 | for line in fp.read().split("\n"): 90 | lines.append(line.strip()) 91 | return lines 92 | 93 | def _save_flow_token( 94 | self, 95 | response: "requests.models.Response", 96 | exception: "tp.Optional[tp.Any]" = None, 97 | where = None 98 | ) -> "tp.Dict": 99 | """ 100 | Store new flow_token in "self._flow_token". 101 | 102 | Parameters: 103 | response (requests.models.Response): response from task request 104 | exception (Optional[Any]): Optional raise an exception if task response contains errors 105 | Returns: 106 | response's json 107 | """ 108 | 109 | j = response.json() 110 | if exception is not None: 111 | self._validate_task_response(j, exception, where) 112 | self._flow_token = j["flow_token"] 113 | return j 114 | 115 | def _set_guest_token(self): 116 | """ 117 | Set guest token in the object's session headers (x-guest-token). 118 | """ 119 | 120 | r = self.session.post(TWITTER_ACTIVATE_EP) 121 | self.session.headers["x-guest-token"] = r.json()["guest_token"] 122 | self.session.cookies.set("gt", self.session.headers["x-guest-token"]) 123 | 124 | def _set_flow_token(self): 125 | """ 126 | Set the initial flow token to complete following tasks 127 | """ 128 | 129 | r = self.session.post( 130 | TWITTER_FLOWTOKEN_EP, json={"input_flow_data":{"flow_context":{"debug_overrides":{},"start_location":{"location":"unknown"}}},"subtask_versions":{"action_list":2,"alert_dialog":1,"app_download_cta":1,"check_logged_in_account":1,"choice_selection":3,"contacts_live_sync_permission_prompt":0,"cta":7,"email_verification":2,"end_flow":1,"enter_date":1,"enter_email":2,"enter_password":5,"enter_phone":2,"enter_recaptcha":1,"enter_text":5,"enter_username":2,"generic_urt":3,"in_app_notification":1,"interest_picker":3,"js_instrumentation":1,"menu_dialog":1,"notifications_permission_prompt":2,"open_account":2,"open_home_timeline":1,"open_link":1,"phone_verification":4,"privacy_options":1,"security_key":3,"select_avatar":4,"select_banner":2,"settings_list":7,"show_code":1,"sign_up":2,"sign_up_review":4,"tweet_selection_urt":1,"update_users":1,"upload_media":1,"user_recommendations_list":4,"user_recommendations_urt":1,"wait_spinner":3,"web_modal":1}}) 131 | self._save_flow_token(r, where="_set_flow_token") 132 | 133 | def _begin_verification(self): 134 | """ 135 | It is used to send the OTP verification code to email 136 | """ 137 | 138 | self.session.get("https://twitter.com/i/api/1.1/account/personalization/p13n_preferences.json") 139 | self.session.post( 140 | TWITTER_BEGINVERIFICATION_EP, json={"email": self.email, "display_name": self.name, "flow_token": self._flow_token}) 141 | 142 | def _is_email_ok(self, email: str) -> bool: 143 | """ 144 | Check if email is valid and available to be used. 145 | 146 | Parameters: 147 | email (str): the email you want to check 148 | Returns: 149 | true if email is valid and available, otherwise false 150 | """ 151 | 152 | r = self.session.get( 153 | TWITTER_EMAIL_EXISTS_EP, params={"email": email}) 154 | if r.status_code < 200 or r.status_code > 299: 155 | return False 156 | 157 | j = r.json() 158 | return j["valid"] and not j["taken"] 159 | 160 | def submit_verification_code(self, code: str, captcha: str): 161 | """ 162 | Complete the "Submit Verification Code" task; it also sets username attribute. 163 | 164 | Parameters: 165 | code (str): the received Twitter's OTP 166 | captcha (str): solved and valid funcaptcha value 167 | """ 168 | 169 | r = self.session.post( 170 | TWITTER_TASK_EP, json={"flow_token":self._flow_token,"subtask_inputs":[{"subtask_id":"Signup","sign_up":{"link":"email_next_link","name":self.name,"email":self.email,"birthday":{"day":15,"month":2,"year":1990}}},{"subtask_id":"SignupSettingsListEmail","settings_list":{"setting_responses":[{"key":"allow_emails_about_activity","response_data":{"boolean_data":{"result":False}}},{"key":"find_by_email","response_data":{"boolean_data":{"result":False}}},{"key":"personalize_ads","response_data":{"boolean_data":{"result":False}}}],"link":"next_link"}},{"subtask_id":"SignupReview","sign_up_review":{"link":"signup_with_email_next_link"}},{"subtask_id":"ArkoseEmail","web_modal":{"completion_deeplink":f"twitter://onboarding/web_modal/next_link?access_token={captcha}","link":"signup_with_email_next_link"}},{"subtask_id":"EmailVerification","email_verification":{"code":code,"email":self.email,"link":"next_link"}}]}) 171 | j = self._save_flow_token(r, exceptions.FailedToCreate, where="submit_verification_code") 172 | self.username = j["subtasks"][0]["enter_password"]["username"] 173 | 174 | def _submit_password(self): 175 | """ 176 | Complete the "Submit Password" task. 177 | """ 178 | 179 | self.session.post(TWITTER_PASSWORDSTRENGTH_EP, data={"password": self.password, "username": self.username}).json() 180 | r = self.session.post( 181 | TWITTER_TASK_EP, json={"flow_token":self._flow_token,"subtask_inputs":[{"subtask_id":"EnterPassword","enter_password":{"password":self.password,"link":"next_link"}}]}) 182 | self._save_flow_token(r, exceptions.FailedToCreate, where="_submit_password") 183 | 184 | def _upload_pfp(self, pfp_name: str): 185 | """ 186 | Upload a profile picture. 187 | 188 | Parameters: 189 | pfp_name (str): file name of the profile picture you want to use (it must be located in the /assets/pfps folder) 190 | """ 191 | 192 | r = self.session.post( 193 | TWITTER_TASK_EP, json={"flow_token": self._flow_token, "subtask_inputs": [ 194 | {"subtask_id": "SelectAvatar", "select_avatar": {"link": "next_link"}}]}) 195 | self._save_flow_token(r, exceptions.BadProxy, where="_upload_pfp") 196 | 197 | path = os.path.sep.join([_ASSETS_DIR, "pfp", pfp_name]) 198 | self._upload_image(path, TWITTER_UPDATEPFP_EP) 199 | 200 | def _upload_banner(self, banner_name: str): 201 | """ 202 | Upload a banner. 203 | 204 | Parameters: 205 | banner_name (str): file name of the banner you want to use (it must be located in the /assets/banners folder) 206 | """ 207 | 208 | path = os.path.sep.join([_ASSETS_DIR, "banners", banner_name]) 209 | self._upload_image(path, TWITTER_UPDATEBANNER_EP, "banner_image") 210 | 211 | def _upload_image(self, file_path: str, update_profile_ep: str, media_category: "tp.Optional[str]" = None): 212 | """ 213 | Upload a generic image. 214 | 215 | Parameters: 216 | file_path (str): path of which image you want to use 217 | update_profile_ep (str): endpoint for profile updating 218 | media_category (str): "banner_image" for banner, empty for pfp 219 | """ 220 | 221 | file_size = os.path.getsize(file_path) 222 | r = self.session.post( 223 | TWITTER_UPLOAD_EP, params={"command": "INIT", "total_bytes": file_size, "media_type": "image/jpeg", "media_category": media_category}) 224 | j = r.json() 225 | if not ("media_id_string" in j): 226 | raise exceptions.FailedToCreate 227 | 228 | media_id = j["media_id_string"] 229 | 230 | file = open(file_path, "rb") 231 | bytes_sent, segment_id = 0, 0 232 | while bytes_sent < file_size: 233 | chunk = file.read(4*1024*1024) 234 | self.session.post( 235 | TWITTER_UPLOAD_EP, 236 | files={"media": chunk}, 237 | params={"command": "APPEND", "media_id": media_id, "media_type": "image/jpeg", "segment_index": segment_id}) 238 | 239 | bytes_sent += file.tell() 240 | segment_id += 1 241 | 242 | media_id = self.session.post(TWITTER_UPLOAD_EP, params={"command": "FINALIZE", "media_id": media_id}) \ 243 | .json()["media_id_string"] 244 | 245 | self.session.post( 246 | update_profile_ep, 247 | data={"include_profile_interstitial_type": 1, "include_blocking": 1, "include_blocked_by": 1, 248 | "include_followed_by": 1, "include_want_retweets": 1, "include_mute_edge": 1, "include_can_dm": 1, 249 | "include_can_media_tag": 1, "include_ext_has_nft_avatar": 1, "include_ext_is_blue_verified": 1, 250 | "skip_status": 1, "return_user": True, "media_id": media_id}) 251 | 252 | def _skip_tasks(self): 253 | """ 254 | It skips the "UsernameEntryBio" task and the "NotificationsPermissionPrompt" task. 255 | """ 256 | 257 | r = self.session.post( 258 | TWITTER_TASK_EP, json={"flow_token":self._flow_token,"subtask_inputs":[{"subtask_id":"UsernameEntryBio","enter_username":{"link":"skip_link"}}]}) 259 | self._save_flow_token(r, exceptions.FailedToCreate, where="_skip_tasks_1") 260 | 261 | r = self.session.post( 262 | TWITTER_TASK_EP, json={"flow_token":self._flow_token,"subtask_inputs":[{"subtask_id":"NotificationsPermissionPrompt","notifications_permission_prompt":{"link":"skip_link"}}]}) 263 | self._save_flow_token(r, exceptions.FailedToCreate, where="_skip_tasks_2") 264 | 265 | def _follow_recommendation(self): 266 | """ 267 | It follows the recommended profile (Elon Musk). 268 | """ 269 | 270 | r = self.session.post( 271 | TWITTER_TASK_EP, json={"flow_token":self._flow_token,"subtask_inputs":[{"subtask_id":"UserRecommendationsURTFollowGating","user_recommendations_urt":{"link":"next_link","selected_user_recommendations":["44196397"]}}]}) 272 | self._save_flow_token(r, where="_follow_recommendation") 273 | 274 | def _create_tweet(self, text: str): 275 | """ 276 | It posts a tweet. 277 | 278 | Parameters: 279 | text (str): content of the tweet 280 | """ 281 | 282 | self.session.post( 283 | TWITTER_CREATETWEET_EP, json={"variables":{"tweet_text":text,"media":{"media_entities":[],"possibly_sensitive":False},"withDownvotePerspective":False,"withReactionsMetadata":False,"withReactionsPerspective":False,"withSuperFollowsTweetFields":True,"withSuperFollowsUserFields":True,"semantic_annotation_ids":[],"dark_request":False},"features":{"tweetypie_unmention_optimization_enabled":True,"responsive_web_uc_gql_enabled":True,"vibe_api_enabled":True,"responsive_web_edit_tweet_api_enabled":True,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":True,"interactive_text_enabled":True,"responsive_web_text_conversations_enabled":False,"responsive_web_twitter_blue_verified_badge_is_enabled":True,"verified_phone_label_enabled":False,"standardized_nudges_misinfo":True,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":False,"responsive_web_graphql_timeline_navigation_enabled":True,"responsive_web_enhance_cards_enabled":True},"queryId":"JPjstjvQ-KCFmAR997gVPQ"}) 284 | 285 | def _update_profile(self, bio_text: str, location_text: str): 286 | """ 287 | It sets a biography. 288 | 289 | Parameters: 290 | bio_text (str): content of biography 291 | location_text (str): content of location field 292 | """ 293 | 294 | self.session.post( 295 | TWITTER_UPDATEPROFILE_EP, data={"birthdate_day": 15, "birthdate_month": 2, "birthdate_year": 1990, "birthdate_visibility": "self", "birthdate_year_visibility": "self", "displayNameMaxLength": 50, "name": self.name, "description": bio_text, "location": location_text}) 296 | 297 | def init(self): 298 | self._set_guest_token() 299 | self._set_flow_token() 300 | self._begin_verification() 301 | 302 | if not self._is_email_ok(self.email): 303 | raise exceptions.InvalidEmail 304 | 305 | def finalize(self): 306 | self._submit_password() 307 | self._upload_pfp(random.choice(self._pfps)) 308 | # self._skip_tasks() 309 | # self._follow_recommendation() 310 | 311 | for tweet in random.choices(self._tweets, k=2): 312 | self._create_tweet(tweet) 313 | self._update_profile(random.choice(self._bios), random.choice(self._locations)) 314 | self._upload_banner(random.choice(self._banners)) 315 | 316 | def get_auth_token(self) -> str: 317 | """ 318 | Get the account's auth token. 319 | 320 | Returns: 321 | account's token used to authorize subsequent requests for this Twitter account. 322 | """ 323 | 324 | return self.session.cookies.get("auth_token") 325 | -------------------------------------------------------------------------------- /twitter/eps.py: -------------------------------------------------------------------------------- 1 | TWITTER_AUTHORIZATION_HEADER = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA" 2 | TWITTER_ACTIVATE_EP = "https://api.twitter.com/1.1/guest/activate.json" 3 | TWITTER_FLOWTOKEN_EP = "https://twitter.com/i/api/1.1/onboarding/task.json?flow_name=signup" 4 | TWITTER_BEGINVERIFICATION_EP = "https://twitter.com/i/api/1.1/onboarding/begin_verification.json" 5 | TWITTER_TASK_EP = "https://twitter.com/i/api/1.1/onboarding/task.json" 6 | TWITTER_PASSWORDSTRENGTH_EP = "https://twitter.com/i/api/1.1/account/password_strength.json" 7 | TWITTER_UPLOAD_EP = "https://upload.twitter.com/1.1/media/upload.json" 8 | TWITTER_UPDATEPFP_EP = "https://twitter.com/i/api/1.1/account/update_profile_image.json" 9 | TWITTER_UPDATEBANNER_EP = "https://twitter.com/i/api/1.1/account/update_profile_banner.json" 10 | TWITTER_CREATETWEET_EP = "https://twitter.com/i/api/graphql/JPjstjvQ-KCFmAR997gVPQ/CreateTweet" 11 | TWITTER_UPDATEPROFILE_EP = "https://twitter.com/i/api/1.1/account/update_profile.json" 12 | TWITTER_EMAIL_EXISTS_EP = "https://twitter.com/i/api/i/users/email_available.json" -------------------------------------------------------------------------------- /twitter/exceptions.py: -------------------------------------------------------------------------------- 1 | class FailedToCreate(Exception): 2 | ... 3 | 4 | 5 | class InvalidEmail(Exception): 6 | ... 7 | 8 | 9 | class BadProxy(Exception): 10 | ... -------------------------------------------------------------------------------- /twitter/models.py: -------------------------------------------------------------------------------- 1 | class Proxy(object): 2 | def __init__(self, user: str, pswd: str, host: str, port: str): 3 | self.user = user 4 | self.pswd = pswd 5 | self.host = host 6 | self.port = port 7 | 8 | def __repr__(self): 9 | return f"" 10 | 11 | def __str__(self): 12 | return f"http://{self.user}:{self.pswd}@{self.host}:{self.port}" --------------------------------------------------------------------------------