├── data ├── config.json ├── config.json.example ├── pfps │ ├── 000fd97ab0040c33ff481ad686d776a1-3515.jpg │ ├── 00a114e6a42178dc12e21633978c27da-5829.jpg │ ├── 00a177d0be4270182e366fb9b8897565-7393.jpg │ ├── 00a6e837043f4a29a387a9467f6343ba.png │ ├── 00aa5ba60f44693faceb18f727df8aee-6761.jpg │ ├── 00aa8185eb856c5e46d703df7bcb2987-4374.jpg │ ├── 00b093febf0c3f26d60454a8b34c0ad4-1990.jpg │ ├── 00b1f51c41ca5502894aeb4794197e37-3267.jpg │ ├── 00b431409f970c69b81257339f01f93a-9892.jpg │ ├── 00b4eeb38b845e0f3f9deed4c2445973-9339.jpg │ ├── 00b857fc38045f3838fb1f38fc8b6001-2613.jpg │ ├── 00bbc248fd55ead03d62d251294c0acb.png │ ├── 00bc7bdd38b34326cede8e189642e234-3869.jpg │ ├── 00bd3c8f2982899013cf39c1c9a54312-2381.jpg │ ├── 00bfc5bc4ddd8e2e4aa8f9829f92f0b4-7746.jpg │ └── 00c9c4bbae80542f9b3480a9a3fb4039-7531.jpg ├── proxies.txt └── usernames.txt ├── errors.log ├── exceptions.py ├── helpers ├── __init__.py ├── captcha.py ├── constants.py ├── email.py ├── exceptions.py ├── instrumentation.so ├── oauth.py ├── twitter.py └── utils.py ├── main.py ├── output └── tokens.txt └── requirements.txt /data/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "threads": 5, 3 | "capsolver_key": "CAP-123", 4 | "yescaptcha_key": "1234", 5 | "allowed_captcha_solvers": ["capsolver"], 6 | "kopeechka_key": "1234", 7 | "account_password": "IHateFaggots45!", 8 | "accepted_email_domains": ["outlook"], 9 | "use_pfp": true, 10 | "use_username": true 11 | } 12 | -------------------------------------------------------------------------------- /data/config.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "threads": 5, 3 | "capsolver_key": "CAP-345", 4 | "allowed_captcha_solvers": ["capsolver", "yescaptcha"], 5 | "kopeechka_key": "1234213213", 6 | "account_password": "ddadad21321432!", 7 | "accepted_email_domains": ["outlook"], 8 | "use_pfp": false, 9 | "use_username": true 10 | } 11 | -------------------------------------------------------------------------------- /data/pfps/000fd97ab0040c33ff481ad686d776a1-3515.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/000fd97ab0040c33ff481ad686d776a1-3515.jpg -------------------------------------------------------------------------------- /data/pfps/00a114e6a42178dc12e21633978c27da-5829.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00a114e6a42178dc12e21633978c27da-5829.jpg -------------------------------------------------------------------------------- /data/pfps/00a177d0be4270182e366fb9b8897565-7393.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00a177d0be4270182e366fb9b8897565-7393.jpg -------------------------------------------------------------------------------- /data/pfps/00a6e837043f4a29a387a9467f6343ba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00a6e837043f4a29a387a9467f6343ba.png -------------------------------------------------------------------------------- /data/pfps/00aa5ba60f44693faceb18f727df8aee-6761.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00aa5ba60f44693faceb18f727df8aee-6761.jpg -------------------------------------------------------------------------------- /data/pfps/00aa8185eb856c5e46d703df7bcb2987-4374.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00aa8185eb856c5e46d703df7bcb2987-4374.jpg -------------------------------------------------------------------------------- /data/pfps/00b093febf0c3f26d60454a8b34c0ad4-1990.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00b093febf0c3f26d60454a8b34c0ad4-1990.jpg -------------------------------------------------------------------------------- /data/pfps/00b1f51c41ca5502894aeb4794197e37-3267.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00b1f51c41ca5502894aeb4794197e37-3267.jpg -------------------------------------------------------------------------------- /data/pfps/00b431409f970c69b81257339f01f93a-9892.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00b431409f970c69b81257339f01f93a-9892.jpg -------------------------------------------------------------------------------- /data/pfps/00b4eeb38b845e0f3f9deed4c2445973-9339.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00b4eeb38b845e0f3f9deed4c2445973-9339.jpg -------------------------------------------------------------------------------- /data/pfps/00b857fc38045f3838fb1f38fc8b6001-2613.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00b857fc38045f3838fb1f38fc8b6001-2613.jpg -------------------------------------------------------------------------------- /data/pfps/00bbc248fd55ead03d62d251294c0acb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00bbc248fd55ead03d62d251294c0acb.png -------------------------------------------------------------------------------- /data/pfps/00bc7bdd38b34326cede8e189642e234-3869.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00bc7bdd38b34326cede8e189642e234-3869.jpg -------------------------------------------------------------------------------- /data/pfps/00bd3c8f2982899013cf39c1c9a54312-2381.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00bd3c8f2982899013cf39c1c9a54312-2381.jpg -------------------------------------------------------------------------------- /data/pfps/00bfc5bc4ddd8e2e4aa8f9829f92f0b4-7746.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00bfc5bc4ddd8e2e4aa8f9829f92f0b4-7746.jpg -------------------------------------------------------------------------------- /data/pfps/00c9c4bbae80542f9b3480a9a3fb4039-7531.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/data/pfps/00c9c4bbae80542f9b3480a9a3fb4039-7531.jpg -------------------------------------------------------------------------------- /data/proxies.txt: -------------------------------------------------------------------------------- 1 | username:password@host:port 2 | -------------------------------------------------------------------------------- /errors.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/errors.log -------------------------------------------------------------------------------- /exceptions.py: -------------------------------------------------------------------------------- 1 | """Contains exceptions for the gen""" 2 | 3 | 4 | class GuestTokenError(Exception): 5 | """Raised when a client fails to grab guest token""" 6 | 7 | 8 | class FlowInitError(Exception): 9 | """Raised when there is an error while initiating the signup flow""" 10 | 11 | 12 | class EmailFlowError(Exception): 13 | """Raised when there is an error while filling the email flow""" 14 | 15 | 16 | class PhoneFlowError(Exception): 17 | """Raised when there is an error while filling the phone flow""" 18 | 19 | 20 | class PasswordFlowError(Exception): 21 | """Raised when there is an error while filling the password flow""" 22 | 23 | 24 | class AvatarFlowError(Exception): 25 | """Raised when there is an error while setting an avatar""" 26 | 27 | 28 | class BioFlowError(Exception): 29 | """Raised when there is an error while setting a bio""" 30 | 31 | 32 | class UsernameFlowError(Exception): 33 | """Raised when there is an error while setting a username""" 34 | 35 | 36 | class PemissionFlowError(Exception): 37 | """Raised when there is an error while setting permissions""" 38 | 39 | 40 | class LanguageFlowError(Exception): 41 | """Raised when there is an error while setting a language""" 42 | 43 | 44 | class NotificationsFlowError(Exception): 45 | """Raised when there is an error while setting notifications settings""" 46 | -------------------------------------------------------------------------------- /helpers/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from colorlog import ColoredFormatter 4 | 5 | from . import captcha 6 | from . import constants 7 | from . import email 8 | from . import oauth 9 | from . import twitter 10 | from . import utils 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | colored_formatter = ColoredFormatter( 15 | "%(log_color)s%(asctime)s - %(levelname)s - %(message)s", 16 | log_colors={ 17 | "DEBUG": "cyan", 18 | "INFO": "green", 19 | "WARNING": "yellow", 20 | "ERROR": "red", 21 | "CRITICAL": "bold_red", 22 | }, 23 | ) 24 | 25 | file_handler = logging.FileHandler("errors.log") 26 | file_handler.setLevel(logging.CRITICAL) 27 | file_handler.setFormatter( 28 | logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") 29 | ) 30 | logger.addHandler(file_handler) 31 | 32 | console_handler = logging.StreamHandler() 33 | console_handler.setFormatter(colored_formatter) 34 | logger.addHandler(console_handler) 35 | 36 | logger.setLevel(logging.INFO) 37 | -------------------------------------------------------------------------------- /helpers/captcha.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import requests 4 | 5 | from . import exceptions 6 | 7 | 8 | class Capsolver: 9 | def __init__(self, api_key: str) -> None: 10 | self.api_key = api_key 11 | self.session = requests.Session() 12 | 13 | @property 14 | def name(self) -> str: 15 | return "Capsolver" 16 | 17 | @property 18 | def create_payload(self) -> dict: 19 | return { 20 | "clientKey": self.api_key, 21 | "task": { 22 | "type": "FunCaptchaTaskProxyLess", 23 | "websiteURL": "https://mobile.twitter.com/i/flow/signup", 24 | "websitePublicKey": "2CB16598-CB82-4CF7-B332-5990DB66F3AB", 25 | "funcaptchaApiJSSubdomain": "https://client-api.arkoselabs.com", 26 | }, 27 | } 28 | 29 | def solve_captcha(self) -> str: 30 | task_create = self.session.post( 31 | "https://api.capsolver.com/createTask", 32 | json=self.create_payload, 33 | ) 34 | task = task_create.json() 35 | if task.get("errorId", 1): 36 | raise exceptions.TaskCreateError( 37 | f"Error while creating task: {task['errorDescription']}" 38 | ) 39 | task_id = task["taskId"] 40 | task_results_payload = {"clientKey": self.api_key, "taskId": task_id} 41 | 42 | get_task_results = self.session.post( 43 | "https://api.capsolver.com/getTaskResult", 44 | json=task_results_payload, 45 | ) 46 | task_results = get_task_results.json() 47 | while task_results["status"] == "processing": 48 | task_results = self.session.post( 49 | "https://api.capsolver.com/getTaskResult", 50 | json=task_results_payload, 51 | ).json() 52 | time.sleep(2) 53 | if task_results["status"] == "error": 54 | raise exceptions.SolvingError( 55 | f"Error while solving task: {task_results['errorDescription']}" 56 | ) 57 | return task_results["solution"]["token"] 58 | 59 | class Yescaptcha: 60 | def __init__(self, api_key: str, *args, **kwargs) -> None: 61 | self.api_key = api_key 62 | self.session = requests.Session() 63 | 64 | @property 65 | def name(self) -> str: 66 | return "Yescaptcha" 67 | 68 | @property 69 | def create_payload(self) -> dict: 70 | return { 71 | "clientKey": self.api_key, 72 | "task": { 73 | "type": "FunCaptchaTaskProxyless", 74 | "websiteURL": "https://mobile.twitter.com/i/flow/signup", 75 | "websitePublicKey": "2CB16598-CB82-4CF7-B332-5990DB66F3AB", 76 | "funcaptchaApiJSSubdomain": "https://client-api.arkoselabs.com" 77 | } 78 | } 79 | 80 | def solve_captcha(self) -> str: 81 | task_create = self.session.post( 82 | "https://api.yescaptcha.com/createTask", json=self.create_payload 83 | ) 84 | task = task_create.json() 85 | if task.get("errorId", 1) != 0: 86 | raise exceptions.TaskCreateError( 87 | f"Error while creating task: {task['errorDescription']} ({task['errorCode']})" 88 | ) 89 | 90 | task_id = task["taskId"] 91 | task_results_payload = {"clientKey": self.api_key, "taskId": task_id} 92 | get_task_results = self.session.post( 93 | "https://api.yescaptcha.com/getTaskResult", json=task_results_payload 94 | ) 95 | task_results = get_task_results.json() 96 | 97 | attempts = 0 98 | while task_results.get("status", "error") == "processing": 99 | if attempts >= 60: 100 | raise exceptions.SolvingError( 101 | "Error while solving task: Max attempts reached" 102 | ) 103 | task_results = self.session.post( 104 | "https://api.yescaptcha.com/getTaskResult", 105 | timeout=30, 106 | json=task_results_payload, 107 | ).json() 108 | attempts += 1 109 | time.sleep(2) 110 | 111 | if task_results["errorId"] != 0: 112 | raise exceptions.SolvingError( 113 | f"Error while solving task: {task_results['errorDescription']} ({task_results['errorCode']})" 114 | ) 115 | return task_results["solution"]["gRecaptchaResponse"] 116 | -------------------------------------------------------------------------------- /helpers/constants.py: -------------------------------------------------------------------------------- 1 | from typing import Final, Dict 2 | 3 | BASE_URL: Final[str] = "https://api.twitter.com/1.1/onboarding/task.json" 4 | 5 | FLOW_INIT_PARAMS: Final[Dict[str, str]] = { 6 | "api_version": "2", 7 | "ext": "highlightedLabel,mediaColor", 8 | "flow_name": "welcome", 9 | "include_entities": "1", 10 | "include_profile_interstitial_type": "true", 11 | "include_profile_location": "true", 12 | "include_user_entities": "true", 13 | "include_user_hashtag_entities": "true", 14 | "include_user_mention_entities": "true", 15 | "include_user_symbol_entities": "true", 16 | "known_device_token": "", 17 | "sim_country_code": "GB", 18 | } 19 | 20 | FLOW_INIT_PAYLOAD: Final[Dict] = { 21 | "component_versions": { 22 | "spacer": 1, 23 | "progress_indicator": 1, 24 | "settings_group": 1, 25 | "card_wrapper": 1, 26 | "image": 1, 27 | "action": 1, 28 | "button": 1, 29 | "inline_callout": 1, 30 | "button_item": 1, 31 | "precise_location": 1, 32 | "tweet": 1, 33 | "inline_feedback": 1, 34 | "inline_tooltip": 1, 35 | "user": 1, 36 | "list": 1, 37 | "destructive_action": 1, 38 | "static_text": 1, 39 | "alert_example": 1, 40 | "boolean": 1, 41 | "info_item": 1, 42 | "toggle_wrapper": 1, 43 | }, 44 | "input_flow_data": { 45 | "flow_context": {"start_location": {"location": "splash_screen"}} 46 | }, 47 | "subtask_versions": { 48 | "enter_date": 1, 49 | "sign_up": 2, 50 | "enter_username": 3, 51 | "alert_dialog": 1, 52 | "choice_selection": 6, 53 | "privacy_options": 1, 54 | "user_recommendations_list": 5, 55 | "upload_media": 1, 56 | "tweet_selection_urt": 1, 57 | "action_list": 2, 58 | "update_users": 1, 59 | "select_banner": 2, 60 | "js_instrumentation": 1, 61 | "standard": 1, 62 | "settings_list": 7, 63 | "app_locale_update": 1, 64 | "open_home_timeline": 1, 65 | "generic_urt": 3, 66 | "wait_spinner": 3, 67 | "menu_dialog": 1, 68 | "open_account": 2, 69 | "single_sign_on": 1, 70 | "open_external_link": 1, 71 | "select_avatar": 4, 72 | "enter_password": 6, 73 | "cta": 7, 74 | "open_link": 1, 75 | "user_recommendations_urt": 4, 76 | "show_code": 1, 77 | "location_permission_prompt": 2, 78 | "sign_up_review": 5, 79 | "in_app_notification": 1, 80 | "security_key": 3, 81 | "phone_verification": 5, 82 | "contacts_live_sync_permission_prompt": 3, 83 | "check_logged_in_account": 1, 84 | "enter_phone": 2, 85 | "enter_text": 5, 86 | "enter_email": 2, 87 | "web_modal": 2, 88 | "notifications_permission_prompt": 4, 89 | "end_flow": 1, 90 | "alert_dialog_suppress_client_events": 1, 91 | "email_verification": 3, 92 | }, 93 | } 94 | 95 | GENERAL_PARAMS: Final[Dict] = { 96 | "ext": "highlightedLabel,mediaColor", 97 | "include_entities": "1", 98 | "include_profile_interstitial_type": "true", 99 | "include_profile_location": "true", 100 | "include_user_entities": "true", 101 | "include_user_hashtag_entities": "true", 102 | "include_user_mention_entities": "true", 103 | "include_user_symbol_entities": "true", 104 | } 105 | 106 | PHONE_CODE_PAYLOAD: Final[Dict] = { 107 | "flow_token": "", 108 | "subtask_inputs": [ 109 | { 110 | "subtask_id": "SplashScreenWithSso", 111 | "cta": {"link": "signup", "component_values": []}, 112 | }, 113 | { 114 | "subtask_id": "WelcomeFlowStartSignupOpenLink", 115 | "open_link": {"link": "welcome_flow_start_signup", "component_values": []}, 116 | }, 117 | { 118 | "subtask_id": "Signup", 119 | "sign_up": { 120 | "link": "next_link", 121 | "js_instrumentation": {"response": ""}, 122 | "birthday": {"year": "", "month": "", "day": ""}, 123 | "name": "", 124 | "phone_number": "", 125 | }, 126 | }, 127 | { 128 | "subtask_id": "ArkosePhone", 129 | "web_modal": { 130 | "completion_deeplink": 'twitter://onboarding/web_modal/next_link?access_token=captchatokenhere"', 131 | "link": "signup_with_phone_next_link", 132 | }, 133 | }, 134 | { 135 | "subtask_id": "SignupSettingsListPhoneNonEU", 136 | "settings_list": { 137 | "link": "next_link", 138 | "component_values": [], 139 | "setting_responses": [ 140 | { 141 | "key": "twitter_for_web", 142 | "response_data": {"boolean_data": {"result": "false"}}, 143 | } 144 | ], 145 | }, 146 | }, 147 | { 148 | "subtask_id": "SignupReview", 149 | "sign_up_review": { 150 | "link": "signup_with_phone_next_link", 151 | "component_values": [], 152 | }, 153 | }, 154 | { 155 | "subtask_id": "PhoneVerificationAlert", 156 | "alert_dialog": {"link": "next_link", "component_values": []}, 157 | }, 158 | { 159 | "subtask_id": "PhoneVerification", 160 | "phone_verification": { 161 | "code": "", 162 | "component_values": [], 163 | "by_voice": "false", 164 | "normalized_phone": "", 165 | "link": "next_link", 166 | }, 167 | }, 168 | ], 169 | } 170 | 171 | EMAIL_CODE_PAYLOAD: Final[Dict] = { 172 | "flow_token": None, 173 | "subtask_inputs": [ 174 | { 175 | "subtask_id": "SplashScreenWithSso", 176 | "cta": {"link": "signup", "component_values": []}, 177 | }, 178 | { 179 | "subtask_id": "WelcomeFlowStartSignupOpenLink", 180 | "open_link": {"link": "welcome_flow_start_signup", "component_values": []}, 181 | }, 182 | { 183 | "subtask_id": "Signup", 184 | "sign_up": { 185 | "email": None, 186 | "js_instrumentation": {"response": None}, 187 | "name": None, 188 | "birthday": {"year": None, "month": None, "day": None}, 189 | "link": "email_next_link", 190 | }, 191 | }, 192 | { 193 | "subtask_id": "ArkoseEmail", 194 | "web_modal": { 195 | "completion_deeplink": 'twitter://onboarding/web_modal/next_link?access_token=captchatokenhere"', 196 | "link": "signup_with_email_next_link", 197 | }, 198 | }, 199 | { 200 | "subtask_id": "SignupSettingsListEmailNonEU", 201 | "settings_list": { 202 | "link": "next_link", 203 | "component_values": [], 204 | "setting_responses": [ 205 | { 206 | "key": "twitter_for_web", 207 | "response_data": {"boolean_data": {"result": "false"}}, 208 | } 209 | ], 210 | }, 211 | }, 212 | { 213 | "subtask_id": "SignupReview", 214 | "sign_up_review": { 215 | "link": "signup_with_email_next_link", 216 | "component_values": [], 217 | }, 218 | }, 219 | { 220 | "subtask_id": "EmailVerification", 221 | "email_verification": { 222 | "code": None, 223 | "component_values": [], 224 | "email": None, 225 | "link": "next_link", 226 | }, 227 | }, 228 | ], 229 | } 230 | 231 | PASSWORD_FLOW_PAYLOAD: Final[Dict] = { 232 | "flow_token": None, 233 | "subtask_inputs": [ 234 | { 235 | "subtask_id": "EnterPassword", 236 | "enter_password": {"password": None, "link": "next_link"}, 237 | } 238 | ], 239 | } 240 | 241 | AVATAR_FLOW_PAYLOAD: Final[Dict] = { 242 | "flow_token": None, 243 | "subtask_inputs": [ 244 | { 245 | "subtask_id": "OpenAccount", 246 | "open_account": {"link": "next_link", "component_values": []}, 247 | }, 248 | { 249 | "subtask_id": "WelcomeFlowStartAccountSetupOpenLink", 250 | "open_link": { 251 | "link": "welcome_flow_start_account_setup", 252 | "component_values": [], 253 | }, 254 | }, 255 | { 256 | "subtask_id": "SelectAvatar", 257 | "select_avatar": {"link": "next_link", "component_values": []}, 258 | }, 259 | { 260 | "subtask_id": "UploadMedia", 261 | "upload_media": {"link": "next_link", "component_values": []}, 262 | }, 263 | ], 264 | } 265 | 266 | BIO_FLOW_PAYLOAD: Final[Dict] = { 267 | "flow_token": None, 268 | "subtask_inputs": [ 269 | { 270 | "subtask_id": None, 271 | "enter_text": { 272 | "link": "skip_link", 273 | "component_values": [], 274 | }, 275 | } 276 | ], 277 | } 278 | 279 | USERNAME_FLOW_PAYLOAD: Final[Dict] = { 280 | "flow_token": None, 281 | "subtask_inputs": [ 282 | { 283 | "subtask_id": None, 284 | "enter_username": {"link": "next_link", "username": None}, 285 | } 286 | ], 287 | } 288 | 289 | NOTIFICATION_FLOW_PAYLOAD: Final[Dict] = { 290 | "flow_token": None, 291 | "subtask_inputs": [ 292 | { 293 | "subtask_id": None, 294 | "notifications_permission_prompt": { 295 | "link": "skip_link", 296 | "component_values": [], 297 | }, 298 | } 299 | ], 300 | } 301 | 302 | PERMISSION_FLOW_PAYLOAD: Final[Dict] = { 303 | "flow_token": None, 304 | "subtask_inputs": [ 305 | { 306 | "subtask_id": None, 307 | "contacts_live_sync_permission_prompt": { 308 | "link": "skip_link", 309 | "component_values": [], 310 | }, 311 | } 312 | ], 313 | } 314 | 315 | LANGUAGE_FLOW_PAYLOAD: Final[Dict] = { 316 | "flow_token": None, 317 | "subtask_inputs": [ 318 | { 319 | "subtask_id": None, 320 | "settings_list": { 321 | "setting_responses": [ 322 | {"key": "en", "response_data": {"boolean_data": {"result": True}}}, 323 | {"key": "fr", "response_data": {"boolean_data": {"result": True}}}, 324 | {"key": "am", "response_data": {"boolean_data": {"result": False}}}, 325 | {"key": "ar", "response_data": {"boolean_data": {"result": False}}}, 326 | {"key": "hy", "response_data": {"boolean_data": {"result": False}}}, 327 | {"key": "eu", "response_data": {"boolean_data": {"result": False}}}, 328 | {"key": "bn", "response_data": {"boolean_data": {"result": False}}}, 329 | {"key": "my", "response_data": {"boolean_data": {"result": False}}}, 330 | {"key": "bg", "response_data": {"boolean_data": {"result": False}}}, 331 | {"key": "ca", "response_data": {"boolean_data": {"result": False}}}, 332 | {"key": "cs", "response_data": {"boolean_data": {"result": False}}}, 333 | {"key": "zh", "response_data": {"boolean_data": {"result": False}}}, 334 | {"key": "ko", "response_data": {"boolean_data": {"result": False}}}, 335 | { 336 | "key": "ckb", 337 | "response_data": {"boolean_data": {"result": False}}, 338 | }, 339 | {"key": "da", "response_data": {"boolean_data": {"result": False}}}, 340 | {"key": "dv", "response_data": {"boolean_data": {"result": False}}}, 341 | {"key": "he", "response_data": {"boolean_data": {"result": False}}}, 342 | {"key": "eo", "response_data": {"boolean_data": {"result": False}}}, 343 | {"key": "et", "response_data": {"boolean_data": {"result": False}}}, 344 | {"key": "fi", "response_data": {"boolean_data": {"result": False}}}, 345 | {"key": "cy", "response_data": {"boolean_data": {"result": False}}}, 346 | {"key": "ka", "response_data": {"boolean_data": {"result": False}}}, 347 | {"key": "ja", "response_data": {"boolean_data": {"result": False}}}, 348 | {"key": "el", "response_data": {"boolean_data": {"result": False}}}, 349 | {"key": "gu", "response_data": {"boolean_data": {"result": False}}}, 350 | {"key": "ht", "response_data": {"boolean_data": {"result": False}}}, 351 | {"key": "hi", "response_data": {"boolean_data": {"result": False}}}, 352 | {"key": "id", "response_data": {"boolean_data": {"result": False}}}, 353 | {"key": "en", "response_data": {"boolean_data": {"result": False}}}, 354 | {"key": "is", "response_data": {"boolean_data": {"result": False}}}, 355 | {"key": "kn", "response_data": {"boolean_data": {"result": False}}}, 356 | {"key": "km", "response_data": {"boolean_data": {"result": False}}}, 357 | {"key": "lo", "response_data": {"boolean_data": {"result": False}}}, 358 | {"key": "lv", "response_data": {"boolean_data": {"result": False}}}, 359 | {"key": "lt", "response_data": {"boolean_data": {"result": False}}}, 360 | {"key": "ml", "response_data": {"boolean_data": {"result": False}}}, 361 | {"key": "ms", "response_data": {"boolean_data": {"result": False}}}, 362 | {"key": "mr", "response_data": {"boolean_data": {"result": False}}}, 363 | {"key": "ne", "response_data": {"boolean_data": {"result": False}}}, 364 | {"key": "no", "response_data": {"boolean_data": {"result": False}}}, 365 | {"key": "or", "response_data": {"boolean_data": {"result": False}}}, 366 | {"key": "nl", "response_data": {"boolean_data": {"result": False}}}, 367 | {"key": "ps", "response_data": {"boolean_data": {"result": False}}}, 368 | {"key": "fa", "response_data": {"boolean_data": {"result": False}}}, 369 | {"key": "pl", "response_data": {"boolean_data": {"result": False}}}, 370 | {"key": "pt", "response_data": {"boolean_data": {"result": False}}}, 371 | {"key": "pa", "response_data": {"boolean_data": {"result": False}}}, 372 | {"key": "ro", "response_data": {"boolean_data": {"result": False}}}, 373 | {"key": "ru", "response_data": {"boolean_data": {"result": False}}}, 374 | {"key": "sr", "response_data": {"boolean_data": {"result": False}}}, 375 | {"key": "sd", "response_data": {"boolean_data": {"result": False}}}, 376 | {"key": "si", "response_data": {"boolean_data": {"result": False}}}, 377 | {"key": "sl", "response_data": {"boolean_data": {"result": False}}}, 378 | {"key": "es", "response_data": {"boolean_data": {"result": False}}}, 379 | {"key": "sv", "response_data": {"boolean_data": {"result": False}}}, 380 | {"key": "tl", "response_data": {"boolean_data": {"result": False}}}, 381 | {"key": "ta", "response_data": {"boolean_data": {"result": False}}}, 382 | {"key": "de", "response_data": {"boolean_data": {"result": False}}}, 383 | {"key": "te", "response_data": {"boolean_data": {"result": False}}}, 384 | {"key": "th", "response_data": {"boolean_data": {"result": False}}}, 385 | {"key": "bo", "response_data": {"boolean_data": {"result": False}}}, 386 | {"key": "tr", "response_data": {"boolean_data": {"result": False}}}, 387 | {"key": "uk", "response_data": {"boolean_data": {"result": False}}}, 388 | {"key": "ug", "response_data": {"boolean_data": {"result": False}}}, 389 | {"key": "hu", "response_data": {"boolean_data": {"result": False}}}, 390 | {"key": "ur", "response_data": {"boolean_data": {"result": False}}}, 391 | {"key": "vi", "response_data": {"boolean_data": {"result": False}}}, 392 | { 393 | "key": "other", 394 | "response_data": {"boolean_data": {"result": False}}, 395 | }, 396 | ], 397 | "link": "next_link", 398 | }, 399 | } 400 | ], 401 | } 402 | -------------------------------------------------------------------------------- /helpers/email.py: -------------------------------------------------------------------------------- 1 | import time 2 | import traceback 3 | from contextlib import contextmanager 4 | from typing import Optional, List 5 | 6 | import tls_client 7 | 8 | from . import exceptions 9 | 10 | 11 | class Kopeechka: 12 | def __init__(self, api_key: str, accepted_domains: List[str]) -> None: 13 | self.api_key = api_key 14 | self.session = tls_client.Session( 15 | client_identifier="chrome_118", random_tls_extension_order=True 16 | ) 17 | self.mail_types = ",".join([mail.upper() for mail in accepted_domains]) 18 | 19 | @property 20 | def base_url(self) -> str: 21 | return "https://api.kopeechka.store" 22 | 23 | @property 24 | def base_create_mail(self) -> tuple[str, dict]: 25 | url = self.base_url + "/mailbox-get-email" 26 | params = { 27 | "site": "https://twitter.com/", 28 | "mail_type": self.mail_types, 29 | "token": self.api_key, 30 | "password": "0", 31 | "type": "/json", 32 | "api": "2.0", 33 | } 34 | return url, params 35 | 36 | def base_get_messages(self, activation_id: str) -> tuple[str, dict]: 37 | url = self.base_url + "/mailbox-get-message" 38 | params = { 39 | "id": int(activation_id), 40 | "token": self.api_key, 41 | "full": "0", 42 | "type": "/json", 43 | "api": "2.0", 44 | } 45 | return url, params 46 | 47 | def base_cancel_email(self, activation_id: str) -> tuple[str, dict]: 48 | url = self.base_url + "/mailbox-cancel" 49 | params = { 50 | "id": int(activation_id), 51 | "token": self.api_key, 52 | "type": "/json", 53 | "api": "2.0", 54 | } 55 | return url, params 56 | 57 | @contextmanager 58 | def rent_email(self) -> tuple[str, str]: 59 | id_ = 0 60 | try: 61 | url, params = self.base_create_mail 62 | r = self.session.get(url, params=params) 63 | jsn = r.json() 64 | if jsn["status"] != "OK": 65 | if jsn["status"] == "OUT_OF_STOCK": 66 | return self.rent_email() 67 | raise exceptions.RentError(jsn["value"]) 68 | id_ = jsn["id"] 69 | yield id_, jsn["mail"] 70 | except: 71 | print(traceback.format_exc()) 72 | 73 | finally: 74 | self.cancel_email(id_) 75 | 76 | def get_code(self, activation_id: str, max_retries: Optional[int] = None) -> str: 77 | if not max_retries: 78 | max_retries = 15 79 | url, params = self.base_get_messages(activation_id) 80 | for _ in range(max_retries): 81 | r = self.session.get(url, params=params) 82 | jsn = r.json() 83 | if jsn["status"] != "OK": 84 | if jsn["value"] != "WAIT_LINK": 85 | raise exceptions.GetCodeError(jsn["value"]) 86 | time.sleep(2) 87 | continue 88 | return jsn["value"] 89 | 90 | def cancel_email(self, activation_id: str) -> bool: 91 | url, params = self.base_cancel_email(activation_id) 92 | r = self.session.get(url, params=params) 93 | jsn = r.json() 94 | if jsn["status"] != "OK": 95 | return False 96 | return True 97 | -------------------------------------------------------------------------------- /helpers/exceptions.py: -------------------------------------------------------------------------------- 1 | class RentError(Exception): 2 | """Raised when there is an error renting an email""" 3 | 4 | 5 | class GetCodeError(Exception): 6 | """Raised when there is an error getting a code""" 7 | 8 | 9 | class TaskCreateError(Exception): 10 | """Raised when a task fails to create""" 11 | 12 | 13 | class SolvingError(Exception): 14 | """Raised when a captcha fails to solve""" 15 | 16 | 17 | class JsInstrumentationError(Exception): 18 | """Raised when getting js instrumentation fails""" 19 | -------------------------------------------------------------------------------- /helpers/instrumentation.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/helpers/instrumentation.so -------------------------------------------------------------------------------- /helpers/oauth.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import binascii 3 | import collections 4 | import hashlib 5 | import hmac 6 | import secrets 7 | import string 8 | import time 9 | from urllib.parse import quote 10 | from urllib.parse import urlencode 11 | 12 | from oauthlib import oauth1 13 | 14 | from . import constants 15 | 16 | random_string = lambda length: "".join( 17 | secrets.choice(string.ascii_lowercase + string.ascii_lowercase) 18 | for _ in range(length) 19 | ) 20 | 21 | escape = lambda s: quote(s, safe="~") 22 | 23 | 24 | def generate_nonce(): 25 | random_bytes = b"\x00" + secrets.token_bytes(32) + b"\x00" 26 | b64_encoded = base64.b64encode(random_bytes) 27 | 28 | return b64_encoded.decode() 29 | 30 | 31 | def stringify_parameters(parameters): 32 | output = "" 33 | ordered_parameters = collections.OrderedDict(sorted(parameters.items())) 34 | 35 | counter = 1 36 | for k, v in ordered_parameters.items(): 37 | output += escape(str(k)) + "=" + escape(str(v)) 38 | if counter < len(ordered_parameters): 39 | output += "&" 40 | counter += 1 41 | 42 | return output 43 | 44 | 45 | def SignatureString(data, url, method, payload): 46 | z = { 47 | **data, 48 | **payload, 49 | } 50 | 51 | signature_base_string = ( 52 | method + "&" + escape(url) + "&" + escape(stringify_parameters(z)) 53 | ) 54 | 55 | return signature_base_string 56 | 57 | 58 | def SigningKey(secret): 59 | signingkeys = escape("GgDYlkSvaPxGxC4X8liwpUoqKwwr3lCADbz8A7ADU") + "&" 60 | signingkeys += escape(secret) 61 | 62 | return signingkeys 63 | 64 | 65 | def calculate_signature(signing_key, signature_base_string): 66 | """Calculate the signature using SHA1""" 67 | hashed = hmac.new( 68 | signing_key.encode("utf-8"), signature_base_string.encode("utf-8"), hashlib.sha1 69 | ) 70 | 71 | sig = binascii.b2a_base64(hashed.digest())[:-1] 72 | 73 | return escape(sig) 74 | 75 | 76 | def getAuth(method, url, secret, token, params): 77 | client = oauth1.Client( 78 | "IQKbtAYlXLripLGPWd0HUA", 79 | client_secret="GgDYlkSvaPxGxC4X8liwpUoqKwwr3lCADbz8A7ADU", 80 | resource_owner_key=token, 81 | resource_owner_secret=secret, 82 | signature_method=oauth1.SIGNATURE_HMAC_SHA1, 83 | ) 84 | 85 | if params is None: 86 | params = constants.GENERAL_PARAMS 87 | enc = urlencode(params) 88 | headers = {"Content-Type": "application/x-www-form-urlencoded"} 89 | _, headers, _ = client.sign(url, http_method=method, headers=headers, body=enc) 90 | return headers["Authorization"] 91 | if params == "NO_VALUE": 92 | _, headers, _ = client.sign(url, http_method=method) 93 | return headers["Authorization"] 94 | enc = urlencode(params) 95 | headers = {"Content-Type": "application/x-www-form-urlencoded"} 96 | _, headers, _ = client.sign(url, http_method=method, headers=headers, body=enc) 97 | return headers["Authorization"] 98 | 99 | 100 | def getAuth2(method, url, secret, token, params): 101 | auths = { 102 | "oauth_nonce": random_string(64), 103 | "oauth_timestamp": str(int(time.time())), 104 | "oauth_consumer_key": "IQKbtAYlXLripLGPWd0HUA", 105 | "oauth_token": token, 106 | "oauth_version": "1.0", 107 | "oauth_signature_method": "HMAC-SHA1", 108 | } 109 | 110 | if params is None: 111 | params = constants.GENERAL_PARAMS 112 | signature_string = SignatureString(auths, url, method, params) 113 | signing_key = SigningKey(secret) 114 | 115 | auths["oauth_signature"] = calculate_signature(signing_key, signature_string) 116 | 117 | ordered_parameters = {} 118 | ordered_parameters = collections.OrderedDict(sorted(auths.items())) 119 | auth_header = ('%s="%s"' % (k, v) for k, v in ordered_parameters.items()) 120 | 121 | val = "OAuth " + ", ".join(auth_header) 122 | 123 | return val 124 | -------------------------------------------------------------------------------- /helpers/twitter.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import hashlib 3 | import secrets 4 | import string 5 | from os import path 6 | from typing import List, Dict, Optional 7 | from uuid import uuid4 8 | 9 | import requests 10 | from httpx import Client 11 | 12 | from . import utils 13 | 14 | LIBRARY = ctypes.CDLL("helpers/instrumentation.so") 15 | 16 | class SessionManager: 17 | def __init__(self, proxies: List[str]) -> None: 18 | self.proxies = proxies 19 | 20 | @property 21 | def account_statuses(self) -> Dict[str, str]: 22 | return { 23 | "https://twitter.com/account/access": "LOCKED", 24 | "/i/flow/consent_flow": "CONSENT", 25 | "is suspended and": "SUSPENDED", 26 | "not authenticate you": "DELETED", 27 | } 28 | 29 | def check_token(self, token: str) -> str: 30 | session = self.init_session(token) 31 | check = session.post( 32 | "https://twitter.com/i/api/1.1/account/update_profile.json" 33 | ) 34 | if check.status_code == 200: 35 | return "UNLOCKED" 36 | status = "UNKNOWN" 37 | for key, value in self.account_statuses.items(): 38 | if key in check.text: 39 | status = value 40 | return status 41 | 42 | def init_session(self, token: str) -> Client: 43 | session = Client( 44 | proxies=utils.get_random_proxies(), 45 | timeout=30 46 | ) 47 | session.cookies["auth_token"] = token 48 | self._get_cookies(session) 49 | return session 50 | 51 | def _get_cookies(self, session: Client) -> None: 52 | try: 53 | session.headers = { 54 | "authority": "twitter.com", 55 | "accept": "*/*", 56 | "accept-language": "en-US,en;q=0.7", 57 | "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA", 58 | "content-type": "application/json", 59 | "referer": "https://twitter.com/", 60 | "sec-ch-ua": '"Not/A)Brand";v="99", "Brave";v="120", "Chromium";v="120"', 61 | "sec-ch-ua-mobile": "?0", 62 | "sec-ch-ua-platform": '"Windows"', 63 | "sec-fetch-dest": "empty", 64 | "sec-fetch-mode": "cors", 65 | "sec-fetch-site": "same-origin", 66 | "sec-gpc": "1", 67 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 68 | "x-client-transaction-id": "k5EGS2Mu/OnX/xGtwHtqbZ8/euSDYZUWpn/44FpzElhoSbuNTCnfFpcK+ajyPP/491pZHpMbTSnGQtiP7O5YuwjO74Hikg", 69 | "x-client-uuid": str(uuid4()), 70 | "x-twitter-active-user": "yes", 71 | "x-twitter-auth-type": "OAuth2Session", 72 | "x-twitter-client-language": "en", 73 | } 74 | session.post( 75 | "https://twitter.com/i/api/1.1/account/update_profile.json" 76 | ) 77 | session.headers["x-csrf-token"] = session.cookies.get("ct0") 78 | except TimeoutError: 79 | return 80 | 81 | @staticmethod 82 | def get_file_size(file: str) -> Optional[str]: 83 | try: 84 | return str(path.getsize(file)) 85 | except FileNotFoundError: 86 | print(f"Error: File '{file}' not found.") 87 | return None 88 | 89 | @staticmethod 90 | def calculate_md5(file_path: str): 91 | md5_hash = hashlib.md5() 92 | 93 | with open(file_path, "rb") as file: 94 | for byte_block in iter(lambda: file.read(4096), b""): 95 | md5_hash.update(byte_block) 96 | 97 | return md5_hash.hexdigest() 98 | 99 | def _init_upload(self, session: Client, size: str) -> str: 100 | params = { 101 | "command": "INIT", 102 | "total_bytes": size, 103 | "media_type": "image/jpeg", 104 | "media_category": "tweet_image", 105 | } 106 | 107 | response = session.post( 108 | "https://upload.twitter.com/i/media/upload.json", 109 | params=params, 110 | ) 111 | if response.status_code == 202: 112 | return response.json()["media_id"] 113 | 114 | def _first_append(self, session: Client, media_id: str) -> bool: 115 | headers = { 116 | "authority": "upload.twitter.com", 117 | "accept": "*/*", 118 | "accept-language": "en-US,en;q=0.9", 119 | "access-control-request-headers": "authorization,x-csrf-token,x-twitter-auth-type", 120 | "access-control-request-method": "POST", 121 | "origin": "https://twitter.com", 122 | "referer": "https://twitter.com/", 123 | "sec-fetch-dest": "empty", 124 | "sec-fetch-mode": "cors", 125 | "sec-fetch-site": "same-site", 126 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 127 | } 128 | 129 | params = { 130 | "command": "APPEND", 131 | "media_id": media_id, 132 | "segment_index": "0", 133 | } 134 | response = session.options( 135 | "https://upload.twitter.com/i/media/upload.json", 136 | params=params, 137 | headers=headers, 138 | ) 139 | return response.status_code == 200 140 | 141 | def _upload_content(self, session: Client, media_id: str, file: str) -> bool: 142 | params = { 143 | "command": "APPEND", 144 | "media_id": media_id, 145 | "segment_index": "0", 146 | } 147 | headers = { 148 | "authority": "upload.twitter.com", 149 | "accept": "*/*", 150 | "accept-language": "en-US,en;q=0.6", 151 | "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA", 152 | "origin": "https://twitter.com", 153 | "referer": "https://twitter.com/", 154 | "sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Brave";v="120"', 155 | "sec-ch-ua-mobile": "?0", 156 | "sec-ch-ua-platform": '"Windows"', 157 | "sec-fetch-dest": "empty", 158 | "sec-fetch-mode": "cors", 159 | "sec-fetch-site": "same-site", 160 | "sec-gpc": "1", 161 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 162 | "x-csrf-token": session.headers["x-csrf-token"], 163 | "x-twitter-auth-type": "OAuth2Session", 164 | } 165 | 166 | if not file.startswith("http"): 167 | with open(file, "rb") as f: 168 | file_content = f.read() 169 | else: 170 | file_content = requests.get(file).content 171 | 172 | response = requests.post( 173 | "https://upload.twitter.com/i/media/upload.json", 174 | params=params, 175 | files={"media": file_content}, 176 | cookies=session.cookies, 177 | headers=headers, 178 | ) 179 | return response.status_code == 204 180 | 181 | def _finalize( 182 | self, session: Client, media_id: str, file_hash: Optional[str] = None 183 | ) -> str: 184 | headers = { 185 | "authority": "upload.twitter.com", 186 | "accept": "*/*", 187 | "accept-language": "en-US,en;q=0.9", 188 | "access-control-request-headers": "authorization,x-csrf-token,x-twitter-auth-type", 189 | "access-control-request-method": "POST", 190 | "origin": "https://twitter.com", 191 | "referer": "https://twitter.com/", 192 | "sec-fetch-dest": "empty", 193 | "sec-fetch-mode": "cors", 194 | "sec-fetch-site": "same-site", 195 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", 196 | } 197 | 198 | params = { 199 | "command": "FINALIZE", 200 | "media_id": media_id, 201 | } 202 | if file_hash: 203 | params["original_md5"] = file_hash 204 | first = session.options( 205 | "https://upload.twitter.com/i/media/upload.json", 206 | params=params, 207 | headers=headers, 208 | ) 209 | if first.status_code == 200: 210 | response = session.post( 211 | "https://upload.twitter.com/i/media/upload.json", params=params 212 | ) 213 | if response.status_code == 201: 214 | return response.json()["media_id_string"] 215 | 216 | def upload( 217 | self, session: Client, file: str, confirm_hash: Optional[bool] = None 218 | ) -> Optional[str]: 219 | if not confirm_hash: 220 | file_hash = None 221 | else: 222 | file_hash = self.calculate_md5(file) 223 | if file.startswith("http"): 224 | r = requests.post(file) 225 | size = len(r.content) 226 | else: 227 | size = self.get_file_size(file) 228 | media_id = self._init_upload(session, size) 229 | if media_id is None: 230 | return "no_media_id" 231 | appended = self._first_append(session, media_id) 232 | if not appended: 233 | return "no_append" 234 | uploaded = self._upload_content(session, media_id, file) 235 | if not uploaded: 236 | return "no_upload" 237 | return self._finalize(session, media_id, file_hash=file_hash) 238 | 239 | def set_pfp(self, session: Client, filename: str) -> bool: 240 | media_id = self.upload(session=session, file=filename, confirm_hash=True) 241 | if not media_id: 242 | return False 243 | headers = { 244 | **session.headers, 245 | "content-type": "application/x-www-form-urlencoded", 246 | "x-csrf-token": session.cookies["ct0"], 247 | } 248 | data = { 249 | "include_profile_interstitial_type": "1", 250 | "include_blocking": "1", 251 | "include_blocked_by": "1", 252 | "include_followed_by": "1", 253 | "include_want_retweets": "1", 254 | "include_mute_edge": "1", 255 | "include_can_dm": "1", 256 | "include_can_media_tag": "1", 257 | "include_ext_has_nft_avatar": "1", 258 | "include_ext_is_blue_verified": "1", 259 | "include_ext_verified_type": "1", 260 | "include_ext_profile_image_shape": "1", 261 | "skip_status": "1", 262 | "return_user": "true", 263 | "media_id": media_id, 264 | } 265 | response = session.post( 266 | "https://api.twitter.com/1.1/account/update_profile_image.json", 267 | headers=headers, 268 | data=data, 269 | ) 270 | return response.status_code == 200 271 | 272 | 273 | 274 | def solve_instrumentation(data: str) -> str: 275 | LIBRARY.parseScript.argtypes = [ctypes.c_char_p] 276 | LIBRARY.parseScript.restype = ctypes.c_char_p 277 | 278 | data = data.encode("utf-8") 279 | response = LIBRARY.parseScript(data) 280 | return response.decode() 281 | 282 | def get_web_instrumentation() -> str: 283 | session = requests.Session() 284 | data = session.get( 285 | 'https://twitter.com/i/js_inst?c_name=ui_metrics', 286 | headers={ 287 | "accept": "*/*", 288 | "Referer": "https://twitter.com/i/flow/signup", 289 | "Sec-Fetch-Dest": "script", 290 | "Sec-Fetch-Mode": "no-cors", 291 | "Sec-Fetch-Site": "same-origin" 292 | } 293 | ) 294 | 295 | return solve_instrumentation(data.text) 296 | 297 | 298 | def device_token() ->str: 299 | return "".join( 300 | secrets.choice(string.digits + string.ascii_lowercase + string.ascii_uppercase) 301 | for _ in range(40) 302 | ) 303 | 304 | 305 | def trace_id() -> str: 306 | return "".join( 307 | secrets.choice(string.digits + string.digits + string.ascii_lowercase) 308 | for _ in range(16) 309 | ) 310 | -------------------------------------------------------------------------------- /helpers/utils.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import json 3 | import os 4 | import random 5 | import secrets 6 | import uuid 7 | from ssl import SSLContext 8 | from typing import Dict, List, Tuple 9 | 10 | from attr import dataclass 11 | from httpx import create_ssl_context 12 | 13 | 14 | @dataclass 15 | class Config: 16 | threads: int 17 | capsolver_key: str 18 | yescaptcha_key: str 19 | allowed_captcha_solvers: List[str] 20 | kopeechka_key: str 21 | account_password: str 22 | accepted_email_domains: List[str] 23 | use_pfp: bool 24 | use_username: bool 25 | 26 | 27 | with open("data/config.json", "r", encoding="utf-8") as config_file: 28 | config = json.load(config_file) 29 | config = Config(**config) 30 | 31 | with open("data/proxies.txt", "r", encoding="utf-8") as file: 32 | proxies = file.read().splitlines() 33 | 34 | pfps = os.listdir("data/pfps") 35 | 36 | with open("data/usernames.txt", "r", encoding="utf-8") as file: 37 | usernames = file.read().splitlines() 38 | 39 | 40 | def fill_remaining_chars(s: str) -> str: 41 | remaining_chars = 15 - len(s) 42 | if remaining_chars > 0: 43 | if random.choice([True, False]): 44 | return s + secrets.token_hex(remaining_chars // 2) 45 | return s + str(random.randint(0, 9)) * (remaining_chars // 2) 46 | return s 47 | 48 | 49 | def get_random_username() -> str: 50 | return fill_remaining_chars(random.choice(usernames)) 51 | 52 | 53 | def get_random_pfp() -> str: 54 | with open("data/pfps" + "/" + random.choice(pfps), "rb") as pic: 55 | return base64.b64encode(pic.read()).decode("utf-8") 56 | 57 | 58 | def random_pfp_fiile() -> str: 59 | return "data/pfps" + "/" + random.choice(pfps) 60 | 61 | 62 | def get_random_proxies() -> Dict[str, str]: 63 | proxy = random.choice(proxies) 64 | proxy_dict = {"all://": f"http://{proxy}"} 65 | return proxy_dict 66 | 67 | 68 | def get_uuid() -> str: 69 | return str(uuid.uuid4()).replace("-", "") 70 | 71 | 72 | def get_context() -> SSLContext: 73 | context = create_ssl_context() 74 | cipher1 = "ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH" 75 | 76 | context.set_alpn_protocols(["h2"]) 77 | context.set_ciphers(cipher1) 78 | 79 | return context 80 | 81 | 82 | def birthdate() -> Tuple[int, int, int]: # day, month, year 83 | return random.randint(1, 28), random.randint(1, 12), random.randint(1970, 1999) 84 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import uuid 4 | from logging import Logger 5 | from threading import Lock, Thread 6 | from typing import Final, Dict 7 | 8 | import httpx 9 | from faker import Faker 10 | 11 | import exceptions 12 | import helpers 13 | 14 | FAKE: Final[Faker] = Faker() 15 | 16 | solvers = { 17 | "capsolver": (helpers.captcha.Capsolver, helpers.utils.config.capsolver_key), 18 | "yescaptcha": (helpers.captcha.Yescaptcha, helpers.utils.config.yescaptcha_key), 19 | } 20 | 21 | ENABLED_SOLVERS = [ 22 | solvers[solver.lower()][0](solvers[solver.lower()][1]) 23 | for solver in helpers.utils.config.allowed_captcha_solvers 24 | if solver.lower() in solvers 25 | ] 26 | 27 | assert ( 28 | ENABLED_SOLVERS 29 | ), "Please enable at least 1 captcha solver" 30 | 31 | LOGGER: Final[Logger] = helpers.logger 32 | KOPEECHKA: Final[helpers.email.Kopeechka] = helpers.email.Kopeechka( 33 | api_key=helpers.utils.config.kopeechka_key, 34 | accepted_domains=helpers.utils.config.accepted_email_domains, 35 | ) 36 | 37 | 38 | class TwitterSession: 39 | def __init__(self) -> None: 40 | self.session = httpx.Client( 41 | http2=True, 42 | verify=helpers.utils.get_context(), 43 | timeout=15, 44 | proxies=helpers.utils.get_random_proxies(), 45 | ) 46 | self.name = random.choice([FAKE.name(), random.choice(helpers.utils.usernames)]) 47 | self.device_token = helpers.twitter.device_token() 48 | self.device_id, self.vendor_id, self.uuid = [ 49 | str(uuid.uuid4()).upper() for _ in range(3) 50 | ] 51 | self.birth_day, self.birth_mont, self.birth_year = helpers.utils.birthdate() 52 | self.data: Dict[str, str] = {} 53 | self.auth = {} 54 | self.get_guest_token() 55 | 56 | @property 57 | def os_version(self) -> str: 58 | return "14.1" 59 | 60 | @property 61 | def display_size(self) -> str: 62 | return '1170x2532' 63 | 64 | @property 65 | def client_version(self) -> str: 66 | return "9.34.1" 67 | 68 | @property 69 | def user_agent(self) -> str: 70 | return f"Twitter-iPhone/{self.client_version} iOS/14.8 (Apple;iPhone13,2;;;;;1;2020)" 71 | 72 | @property 73 | def system_user_agent(self) -> str: 74 | return "Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/18A8395 Twitter for iPhone/9.29.2" 75 | 76 | @property 77 | def authorization(self) -> str: 78 | return "AAAAAAAAAAAAAAAAAAAAAAj4AQAAAAAAPraK64zCZ9CSzdLesbE7LB%2Bw4uE%3DVJQREvQNCZJNiz3rHO7lOXlkVOQkzzdsgu6wWgcazdMUaGoUGm" 79 | 80 | @property 81 | def basic_headerss(self) -> Dict[str, str]: 82 | return { 83 | **self.session.headers, 84 | "content-type": "application/json", 85 | "host": "api.twitter.com", 86 | "x-twitter-client-deviceid": self.device_id, 87 | "accept": "application/json", 88 | "x-twitter-client-version": self.client_version, 89 | "x-client-uuid": self.uuid, 90 | "x-twitter-client-language": "en", 91 | "x-b3-traceid": helpers.twitter.trace_id(), 92 | "authorization": f"Bearer {self.authorization}", 93 | "accept-language": "en", 94 | "user-agent": self.user_agent, 95 | "x-twitter-client-limit-ad-tracking": "0", 96 | "x-twitter-api-version": "5", 97 | "x-twitter-client": "Twitter-iPhone", 98 | } 99 | 100 | @property 101 | def basic_headers(self) -> Dict[str, str]: 102 | return { 103 | 'host': 'api.twitter.com', 104 | 'x-twitter-client-deviceid': self.device_id, 105 | 'accept': 'application/json', 106 | 'x-twitter-client-version': self.client_version, 107 | 'x-guest-token': self.session.headers['x-guest-token'], 108 | 'x-client-uuid': self.uuid, 109 | 'x-twitter-client-language': 'en', 110 | 'x-b3-traceid': helpers.twitter.trace_id(), 111 | 'authorization': f'Bearer {self.authorization}', 112 | 'accept-language': 'en', 113 | 'user-agent': self.user_agent, 114 | 'x-twitter-client-limit-ad-tracking': '0', 115 | 'x-twitter-api-version': '5', 116 | 'x-twitter-client': 'Twitter-iPhone', 117 | } 118 | 119 | @property 120 | def advanced_headers(self) -> Dict[str, str]: 121 | return { 122 | **self.session.headers, 123 | "twitter-display-size": self.display_size, 124 | "x-twitter-client-vendorid": self.vendor_id, 125 | "system-user-agent": self.system_user_agent, 126 | "x-b3-traceid": helpers.twitter.trace_id(), 127 | "content-type": "application/json", 128 | "os-version": self.os_version, 129 | } 130 | 131 | @property 132 | def authed_headers(self) -> Dict[str, str]: 133 | return { 134 | **self.advanced_headers, 135 | "timezone": "", 136 | "kdt": self.auth["kdt"], 137 | "x-twitter-active-user": "yes", 138 | "system-user-agent": self.system_user_agent, 139 | "authorization": helpers.oauth.getAuth( 140 | "POST", 141 | helpers.constants.BASE_URL, 142 | self.auth["oauth_secret"], 143 | self.auth["oauth_token"], 144 | None, 145 | ), 146 | } 147 | 148 | def get_guest_token(self) -> None: 149 | headers = { 150 | "host": "api.twitter.com", 151 | "content-type": "application/x-www-form-urlencoded", 152 | "x-twitter-client-deviceid": self.device_id, 153 | "accept": "application/json", 154 | "x-twitter-client-version": self.client_version, 155 | "authorization": f"Bearer {self.authorization}", 156 | "x-client-uuid": self.uuid, 157 | "x-twitter-client-language": "en", 158 | "x-b3-traceid": helpers.twitter.trace_id(), 159 | "accept-language": "en", 160 | "accept-encoding": "gzip, deflate, br", 161 | "user-agent": self.user_agent, 162 | "x-twitter-client-limit-ad-tracking": "0", 163 | "x-twitter-api-version": "5", 164 | "x-twitter-client": "Twitter-iPhone", 165 | } 166 | if 'connection' in self.session.headers: 167 | del self.session.headers['connection'] 168 | response = self.session.post("https://api.twitter.com/1.1/guest/activate.json", headers=headers) #TODO: Headers order is very important 169 | 170 | gt = response.json().get("guest_token") 171 | if gt: 172 | self.session.headers["x-guest-token"] = gt 173 | else: 174 | raise exceptions.GuestTokenError("Failed grabbing guest token") 175 | 176 | def init_flow_token(self) -> str: 177 | url = 'https://api.twitter.com/1.1/onboarding/task.json?' + f'api_version=2&ext=highlightedLabel%2CmediaColor&flow_name=welcome&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true&known_device_token={self.device_token}&sim_country_code=GB' 178 | headers = { 179 | 'host': 'api.twitter.com', 180 | 'user-agent': self.user_agent, 181 | 'x-twitter-client': 'Twitter-iPhone', 182 | 'x-twitter-client-deviceid': self.device_id, 183 | 'twitter-display-size': '1170x2532', 184 | 'x-twitter-client-vendorid': self.vendor_id, 185 | 'system-user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/18A8395 Twitter for iPhone/9.29.2', 186 | 'x-twitter-client-version': self.client_version, 187 | 'x-twitter-client-limit-ad-tracking': '0', 188 | 'x-b3-traceid': helpers.twitter.trace_id(), 189 | 'x-guest-token': self.session.headers['x-guest-token'], 190 | 'accept-language': 'en', 191 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAAAj4AQAAAAAAPraK64zCZ9CSzdLesbE7LB%2Bw4uE%3DVJQREvQNCZJNiz3rHO7lOXlkVOQkzzdsgu6wWgcazdMUaGoUGm', 192 | 'x-twitter-client-language': 'en', 193 | 'x-client-uuid': self.uuid, 194 | 'x-twitter-api-version': '5', 195 | 'accept': 'application/json', 196 | 'content-type': 'application/json', 197 | 'os-version': '14.1', 198 | 'accept-encoding': 'gzip, deflate, br' 199 | } 200 | response = self.session.post( 201 | url, 202 | headers=headers, 203 | json=helpers.constants.FLOW_INIT_PAYLOAD, 204 | ) 205 | jsn = response.json() 206 | if jsn.get("status", "") == "success": 207 | return jsn["flow_token"] 208 | raise exceptions.FlowInitError(f"Error while initiating signup flow: {jsn}") 209 | 210 | def send_phone_otp( 211 | self, phone_number: str, phone_country: str, flow_token: str 212 | ) -> bool: 213 | payload = { 214 | "phone": phone_number, 215 | "sim_country_code": phone_country.upper(), 216 | "flow_token": flow_token, 217 | "use_voice": "false", 218 | } 219 | resp = self.session.post( 220 | "https://api.twitter.com/1.1/onboarding/begin_verification.json", 221 | json=payload, 222 | headers=self.basic_headers, 223 | ) 224 | return "normalized_phone_number" in resp.text 225 | 226 | def send_email_otp(self, email: str, flow_token: str) -> bool: 227 | headers = { 228 | 'host': 'api.twitter.com', 229 | 'x-twitter-client-deviceid': self.device_id, 230 | 'accept': 'application/json', 231 | 'x-twitter-client-version': self.client_version, 232 | 'x-guest-token': self.session.headers['x-guest-token'], 233 | 'x-client-uuid': self.uuid, 234 | 'x-twitter-client-language': 'en', 235 | 'x-b3-traceid': helpers.twitter.trace_id(), 236 | 'authorization': f'Bearer {self.authorization}', 237 | 'accept-language': 'en', 238 | 'user-agent': self.user_agent, 239 | 'x-twitter-client-limit-ad-tracking': '0', 240 | 'x-twitter-api-version': '5', 241 | 'x-twitter-client': 'Twitter-iPhone' 242 | } 243 | payload = { 244 | "email": email, 245 | "display_name": self.name.replace(" ", ""), 246 | "flow_token": flow_token, 247 | "use_voice": "false", 248 | } 249 | response = self.session.post( 250 | "https://api.twitter.com/1.1/onboarding/begin_verification.json", 251 | json=payload, 252 | headers=headers, 253 | ) 254 | return response.status_code == 204 255 | 256 | def phone_code_flow( 257 | self, 258 | phone_number: str, 259 | otp_code: str, 260 | flow_token: str, 261 | js_instrumentation: Dict[str, str], 262 | captcha_key: str, 263 | ) -> str: 264 | payload = helpers.constants.PHONE_CODE_PAYLOAD 265 | input_tasks = payload["subtask_inputs"] 266 | 267 | payload["flow_token"] = flow_token 268 | input_tasks[3]["completion_deeplink"] = input_tasks[3][ 269 | "completion_deeplink" 270 | ].replace("captchatokenhere", captcha_key) 271 | input_tasks[2]["sign_up"]["js_instrumentation"]["response"] = js_instrumentation 272 | input_tasks[2]["sign_up"]["birthday"]["day"] = self.birth_day 273 | input_tasks[2]["sign_up"]["birthday"]["month"] = self.birth_mont 274 | input_tasks[2]["sign_up"]["birthday"]["year"] = self.birth_year 275 | input_tasks[2]["sign_up"]["name"] = self.name 276 | input_tasks[2]["sign_up"]["phone_number"] = phone_number 277 | input_tasks[-1]["phone_verification"]["code"] = otp_code 278 | input_tasks[-1]["phone_verification"]["normalized_phone"] = phone_number 279 | 280 | response = self.session.post( 281 | helpers.constants.BASE_URL, 282 | params=helpers.constants.GENERAL_PARAMS, 283 | json=payload, 284 | headers=self.advanced_headers, 285 | ) 286 | 287 | jsn = response.json() 288 | if jsn.get("status", "") == "success": 289 | return jsn["flow_token"] 290 | raise exceptions.PhoneFlowError(f"Error while Completing phone flow: {jsn}") 291 | 292 | def email_code_flow( 293 | self, 294 | email: str, 295 | otp_code: str, 296 | flow_token: str, 297 | js_instrumentation: str, 298 | captcha_key: str, 299 | ) -> str: 300 | headers = { 301 | 'host': 'api.twitter.com', 302 | 'user-agent': self.user_agent, 303 | 'x-twitter-client': 'Twitter-iPhone', 304 | 'x-twitter-client-deviceid': self.device_id, 305 | 'x-guest-token': self.session.headers['x-guest-token'], 306 | 'twitter-display-size': self.display_size, 307 | 'x-twitter-client-vendorid': self.vendor_id, 308 | 'system-user-agent': self.system_user_agent, 309 | 'x-twitter-client-version': self.client_version, 310 | 'x-twitter-client-limit-ad-tracking': '0', 311 | 'x-b3-traceid': helpers.twitter.trace_id(), 312 | 'accept-language': 'en', 313 | 'authorization': f'Bearer {self.authorization}', 314 | 'x-twitter-client-language': 'en', 315 | 'x-client-uuid': self.uuid, 316 | 'x-twitter-api-version': '5', 317 | 'accept': 'application/json', 318 | 'content-type': 'application/json', 319 | 'os-version': '14.1', 320 | } 321 | 322 | payload = { 323 | "flow_token": flow_token, 324 | "subtask_inputs": [ 325 | { 326 | "subtask_id": "SplashScreenWithSso", 327 | "cta": { 328 | "link": "signup", 329 | "component_values": [] 330 | } 331 | }, 332 | { 333 | "subtask_id": "WelcomeFlowStartSignupOpenLink", 334 | "open_link": { 335 | "link": "welcome_flow_start_signup", 336 | "component_values": [] 337 | } 338 | }, 339 | { 340 | "subtask_id": "Signup", 341 | "sign_up": { 342 | "email": email, 343 | "js_instrumentation": { 344 | "response": js_instrumentation 345 | }, 346 | "name": self.name, 347 | "birthday": { 348 | "year": self.birth_year, 349 | "month": self.birth_mont, 350 | "day": self.birth_day 351 | }, 352 | "link": "email_next_link" 353 | } 354 | }, 355 | {"subtask_id":"ArkosePhone","web_modal":{"completion_deeplink":"twitter://onboarding/web_modal/next_link?access_token="+ captcha_key +"","link":"signup_with_phone_next_link"}}, 356 | { 357 | "subtask_id": "SignupSettingsListEmailNonEU", 358 | "settings_list": { 359 | "link": "next_link", 360 | "component_values": [], 361 | "setting_responses": [ 362 | { 363 | "key": "twitter_for_web", 364 | "response_data": { 365 | "boolean_data": { 366 | "result": 'false' 367 | } 368 | } 369 | } 370 | ] 371 | } 372 | }, 373 | { 374 | "subtask_id": "SignupReview", 375 | "sign_up_review": { 376 | "link": "signup_with_email_next_link", 377 | "component_values": [] 378 | } 379 | }, 380 | { 381 | "subtask_id": "EmailVerification", 382 | "email_verification": { 383 | "code": otp_code, 384 | "component_values": [], 385 | "email": email, 386 | "link": "next_link" 387 | } 388 | } 389 | ] 390 | } 391 | 392 | response = self.session.post( 393 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 394 | json=payload, 395 | headers=headers, 396 | ) 397 | 398 | jsn = response.json() 399 | if jsn.get("status", "") == "success": 400 | return jsn["flow_token"] 401 | raise exceptions.EmailFlowError(f"Error while Completing email flow: {jsn}") 402 | 403 | def password_flow(self, flow_token: str, password: str) -> str: 404 | headers = { 405 | 'host': 'api.twitter.com', 406 | 'user-agent': self.user_agent, 407 | 'x-twitter-client': 'Twitter-iPhone', 408 | 'x-twitter-client-deviceid': self.device_id, 409 | 'x-guest-token': self.session.headers['x-guest-token'], 410 | 'twitter-display-size': self.display_size, 411 | 'x-twitter-client-vendorid': self.vendor_id, 412 | 'system-user-agent': self.system_user_agent, 413 | 'x-twitter-client-version': self.client_version, 414 | 'x-twitter-client-limit-ad-tracking': '0', 415 | 'x-b3-traceid': helpers.twitter.trace_id(), 416 | 'accept-language': 'en', 417 | 'authorization': f'Bearer {self.authorization}', 418 | 'x-twitter-client-language': 'en', 419 | 'x-client-uuid': self.uuid, 420 | 'x-twitter-api-version': '5', 421 | 'accept': 'application/json', 422 | 'content-type': 'application/json', 423 | 'os-version': '14.1', 424 | } 425 | payload = { 426 | "flow_token": flow_token, 427 | "subtask_inputs": [ 428 | { 429 | "subtask_id": "EnterPassword", 430 | "enter_password": { 431 | "link": "next_link", 432 | "component_values": [], 433 | "password": password 434 | } 435 | } 436 | ] 437 | } 438 | 439 | response = self.session.post( 440 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 441 | json=payload, 442 | headers=headers, 443 | ) 444 | jsn = response.json() 445 | if jsn.get("status", "") == "success": 446 | LOGGER.info("Completed password flow") 447 | self.auth["kdt"] = response.headers.get("kdt", "") 448 | self.auth["oauth_token"] = jsn["subtasks"][0]["open_account"]["oauth_token"] 449 | self.auth["oauth_secret"] = jsn["subtasks"][0]["open_account"][ 450 | "oauth_token_secret" 451 | ] 452 | return jsn["flow_token"] 453 | 454 | raise exceptions.PasswordFlowError( 455 | f"Error while filling out password flow: {jsn}" 456 | ) 457 | 458 | def StartSetup(self, flow_token: str): 459 | if "EnterProfileBio" in self.data: 460 | self.bio_flow(flow_token) 461 | elif "Avatar" in self.data: 462 | self.avatar_flow(flow_token) 463 | elif "Username" in self.data: 464 | self.username_flow(flow_token) 465 | elif "Notifications" in self.data: 466 | self.notification_flow(flow_token) 467 | elif self.data == "PermissionPrompt": 468 | self.permission_flow(flow_token) 469 | elif self.data == "LanguageSelectorList": 470 | self.language_flow(flow_token) 471 | 472 | def avatar_flow(self, flow_token: str) -> None: 473 | payload = { 474 | "flow_token": flow_token, 475 | "subtask_inputs": [ 476 | { 477 | "subtask_id": "OpenAccount", 478 | "open_account": { 479 | "link": "next_link", 480 | "component_values": [] 481 | } 482 | }, 483 | { 484 | "subtask_id": "WelcomeFlowStartAccountSetupOpenLink", 485 | "open_link": { 486 | "link": "welcome_flow_start_account_setup", 487 | "component_values": [] 488 | } 489 | }, 490 | { 491 | "subtask_id": "SelectAvatar", 492 | "select_avatar": { 493 | "link": "next_link", 494 | "component_values": [] 495 | } 496 | }, 497 | { 498 | "subtask_id": "UploadMedia", 499 | "upload_media": { 500 | "link": "next_link", 501 | "component_values": [] 502 | } 503 | } 504 | ] 505 | } 506 | 507 | headers = { 508 | 'host': 'api.twitter.com', 509 | 'kdt': self.auth['kdt'], 510 | 'user-agent': self.user_agent, 511 | 'x-twitter-client': 'Twitter-iPhone', 512 | 'x-twitter-client-deviceid': self.device_id, 513 | 'x-twitter-active-user': 'yes', 514 | 'twitter-display-size': self.display_size, 515 | 'x-twitter-client-vendorid': self.vendor_id, 516 | 'system-user-agent': self.system_user_agent, 517 | 'x-twitter-client-version': self.client_version, 518 | 'x-twitter-client-limit-ad-tracking': '0', 519 | 'x-b3-traceid': helpers.twitter.trace_id(), 520 | 'accept-language': 'en', 521 | 'timezone': '', 522 | 'authorization': helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],None), 523 | 'x-twitter-client-language': 'en', 524 | 'x-client-uuid': self.uuid, 525 | 'x-twitter-api-version': '5', 526 | 'accept': 'application/json', 527 | 'content-type': 'application/json', 528 | 'os-version': self.os_version, 529 | } 530 | 531 | response = self.session.post( 532 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 533 | json=payload, 534 | headers=headers, 535 | ) 536 | 537 | jsn = response.json() 538 | if jsn.get("status", "") == "success": 539 | self.data = jsn["subtasks"][0]["subtask_id"] 540 | self.StartSetup(jsn["flow_token"]) 541 | else: 542 | raise exceptions.AvatarFlowError(f"Error while Setting Avatar: {jsn}") 543 | 544 | def bio_flow(self, flow_token: str) -> None: 545 | payload = { 546 | "flow_token": flow_token, 547 | "subtask_inputs": [ 548 | { 549 | "subtask_id": self.data, 550 | "enter_text": { 551 | "link": "skip_link", 552 | "component_values": [], 553 | } 554 | } 555 | ] 556 | } 557 | headers = { 558 | 'host': 'api.twitter.com', 559 | 'user-agent': self.user_agent, 560 | 'x-twitter-client': 'Twitter-iPhone', 561 | 'x-twitter-client-deviceid': self.device_id, 562 | 'x-twitter-active-user': 'yes', 563 | 'twitter-display-size': self.display_size, 564 | 'kdt': self.auth['kdt'], 565 | 'x-twitter-client-vendorid': self.vendor_id, 566 | 'system-user-agent': self.system_user_agent, 567 | 'x-twitter-client-version': self.client_version, 568 | 'x-twitter-client-limit-ad-tracking': '0', 569 | 'x-b3-traceid': helpers.twitter.trace_id(), 570 | 'accept-language': 'en', 571 | 'timezone': '', 572 | 'authorization': helpers.oauth.getAuth("POST", "https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"], None), 573 | 'x-twitter-client-language': 'en', 574 | 'x-client-uuid': self.uuid, 575 | 'x-twitter-api-version': '5', 576 | 'accept': 'application/json', 577 | 'content-type': 'application/json', 578 | 'os-version': self.os_version, 579 | } 580 | response = self.session.post( 581 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 582 | json=payload, 583 | headers=headers, 584 | ) 585 | jsn = response.json() 586 | if jsn.get("status", "") == "success": 587 | LOGGER.debug("[+] Set BIO") 588 | self.data = jsn["subtasks"][0]["subtask_id"] 589 | self.StartSetup(jsn["flow_token"]) 590 | else: 591 | raise exceptions.BioFlowError(f"Error while Setting Bio: {jsn}") 592 | 593 | def username_flow(self, flow_token: str) -> None: 594 | payload = { 595 | "flow_token": flow_token, 596 | "subtask_inputs": [ 597 | { 598 | "subtask_id": self.data, 599 | "enter_username": { 600 | "link": "next_link", 601 | "component_values": [], 602 | "username": "" 603 | } 604 | } 605 | ] 606 | } 607 | input_tasks = payload["subtask_inputs"] 608 | headers = { 609 | 'host': 'api.twitter.com', 610 | 'user-agent': self.user_agent, 611 | 'x-twitter-client': 'Twitter-iPhone', 612 | 'x-twitter-client-deviceid': self.device_id, 613 | 'x-twitter-active-user': 'yes', 614 | 'twitter-display-size': self.display_size, 615 | 'kdt': self.auth['kdt'], 616 | 'x-twitter-client-vendorid': self.vendor_id, 617 | 'system-user-agent': self.system_user_agent, 618 | 'x-twitter-client-version': self.client_version, 619 | 'x-twitter-client-limit-ad-tracking': '0', 620 | 'x-b3-traceid': helpers.twitter.trace_id(), 621 | 'accept-language': 'en', 622 | 'timezone': '', 623 | 'authorization': helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],None), 624 | 'x-twitter-client-language': 'en', 625 | 'x-client-uuid': self.uuid, 626 | 'x-twitter-api-version': '5', 627 | 'accept': 'application/json', 628 | 'content-type': 'application/json', 629 | 'os-version': '14.1', 630 | } 631 | if helpers.utils.config.use_username: 632 | username = helpers.utils.get_random_username() 633 | input_tasks[0]["enter_username"]["username"] = username 634 | else: 635 | username = FAKE.user_name()[:15] 636 | username = helpers.utils.fill_remaining_chars(username) 637 | input_tasks[0]["enter_username"]["username"] = username 638 | 639 | response = self.session.post( 640 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 641 | json=payload, 642 | headers=headers, 643 | ) 644 | jsn = response.json() 645 | if jsn.get("status", "") == "success": 646 | LOGGER.debug("[+] Set Username") 647 | self.data = jsn["subtasks"][0]["subtask_id"] 648 | self.StartSetup(jsn["flow_token"]) 649 | else: 650 | raise exceptions.UsernameFlowError(f"Error while Setting Username: {jsn}") 651 | 652 | def notification_flow(self, flow_token: str) -> None: 653 | payload = { 654 | "flow_token": flow_token, 655 | "subtask_inputs": [ 656 | { 657 | "subtask_id": self.data, 658 | "notifications_permission_prompt": { 659 | "link": "skip_link", 660 | "component_values": [] 661 | } 662 | } 663 | ] 664 | } 665 | headers = { 666 | 'host': 'api.twitter.com', 667 | 'user-agent': self.user_agent, 668 | 'x-twitter-client': 'Twitter-iPhone', 669 | 'x-twitter-client-deviceid': self.device_id, 670 | 'x-twitter-active-user': 'yes', 671 | 'twitter-display-size': self.display_size, 672 | 'kdt': self.auth['kdt'], 673 | 'x-twitter-client-vendorid': self.vendor_id, 674 | 'system-user-agent': self.system_user_agent, 675 | 'x-twitter-client-version': self.client_version, 676 | 'x-twitter-client-limit-ad-tracking': '0', 677 | 'x-b3-traceid': helpers.twitter.trace_id(), 678 | 'accept-language': 'en', 679 | 'timezone': '', 680 | 'authorization': helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],None), 681 | 'x-twitter-client-language': 'en', 682 | 'x-client-uuid': self.uuid, 683 | 'x-twitter-api-version': '5', 684 | 'accept': 'application/json', 685 | 'content-type': 'application/json', 686 | 'os-version': self.os_version, 687 | } 688 | 689 | response = self.session.post( 690 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 691 | json=payload, 692 | headers=headers, 693 | ) 694 | jsn = response.json() 695 | if jsn.get("status", "") == "success": 696 | LOGGER.debug("[+] Set Notifications") 697 | self.data = jsn["subtasks"][0]["subtask_id"] 698 | self.StartSetup(jsn["flow_token"]) 699 | else: 700 | raise exceptions.NotificationsFlowError( 701 | f"Error while Setting notifications: {jsn}" 702 | ) 703 | 704 | def permission_flow(self, flow_token: str) -> None: 705 | payload = { 706 | "flow_token": flow_token, 707 | "subtask_inputs": [ 708 | { 709 | "subtask_id": self.data, 710 | "contacts_live_sync_permission_prompt": { 711 | "link": "skip_link", 712 | "component_values": [] 713 | } 714 | } 715 | ] 716 | } 717 | headers = { 718 | 'host': 'api.twitter.com', 719 | 'user-agent': self.user_agent, 720 | 'x-twitter-client': 'Twitter-iPhone', 721 | 'x-twitter-client-deviceid': self.device_id, 722 | 'x-twitter-active-user': 'yes', 723 | 'kdt': self.auth['kdt'], 724 | 'twitter-display-size': self.display_size, 725 | 'x-twitter-client-vendorid': self.vendor_id, 726 | 'system-user-agent': self.system_user_agent, 727 | 'x-twitter-client-version': self.client_version, 728 | 'x-twitter-client-limit-ad-tracking': '0', 729 | 'x-b3-traceid': helpers.twitter.trace_id(), 730 | 'accept-language': 'en', 731 | 'timezone': '', 732 | 'authorization': helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],None), 733 | 'x-twitter-client-language': 'en', 734 | 'x-client-uuid': self.uuid, 735 | 'x-twitter-api-version': '5', 736 | 'accept': 'application/json', 737 | 'content-type': 'application/json', 738 | 'os-version': self.os_version, 739 | } 740 | 741 | response = self.session.post( 742 | "https://api.twitter.com/1.1/onboarding/task.json?ext=highlightedLabel%2CmediaColor&include_entities=1&include_profile_interstitial_type=true&include_profile_location=true&include_user_entities=true&include_user_hashtag_entities=true&include_user_mention_entities=true&include_user_symbol_entities=true", 743 | json=payload, 744 | headers=headers, 745 | ) 746 | jsn = response.json() 747 | if jsn.get("status", "") == "success": 748 | LOGGER.debug("[+] Set Permissions") 749 | self.data = jsn["subtasks"][0]["subtask_id"] 750 | self.StartSetup(jsn["flow_token"]) 751 | else: 752 | raise exceptions.PemissionFlowError( 753 | f"Error while Setting Permissions: {jsn}" 754 | ) 755 | 756 | def language_flow(self, flow_token: str) -> None: 757 | payload = helpers.constants.LANGUAGE_FLOW_PAYLOAD 758 | payload["flow_token"] = flow_token 759 | input_tasks = payload["subtask_inputs"] 760 | headers = { 761 | 'host': 'api.twitter.com', 762 | 'user-agent': self.user_agent, 763 | 'x-twitter-client': 'Twitter-iPhone', 764 | 'x-twitter-client-deviceid': self.device_id, 765 | 'x-twitter-active-user': 'yes', 766 | 'kdt': self.auth['kdt'], 767 | 'twitter-display-size': self.display_size, 768 | 'x-twitter-client-vendorid': self.vendor_id, 769 | 'system-user-agent': self.system_user_agent, 770 | 'x-twitter-client-version': self.client_version, 771 | 'x-twitter-client-limit-ad-tracking': '0', 772 | 'x-b3-traceid': helpers.twitter.trace_id(), 773 | 'accept-language': 'en', 774 | 'timezone': '', 775 | 'authorization': helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],None), 776 | 'x-twitter-client-language': 'en', 777 | 'x-client-uuid': self.uuid, 778 | 'x-twitter-api-version': '5', 779 | 'accept': 'application/json', 780 | 'content-type': 'application/json', 781 | 'os-version': self.os_version, 782 | } 783 | input_tasks[0]["subtask_id"] = self.data 784 | 785 | response = self.session.post( 786 | helpers.constants.BASE_URL, 787 | json=payload, 788 | headers=headers, 789 | params=helpers.constants.GENERAL_PARAMS, 790 | ) 791 | jsn = response.json() 792 | if jsn.get("status", "") == "success": 793 | LOGGER.debug("[+] Set Languages") 794 | self.data = jsn["subtasks"][0]["subtask_id"] 795 | self.StartSetup(jsn["flow_token"]) 796 | else: 797 | raise exceptions.LanguageFlowError(f"Error while Setting Lanaguages: {jsn}") 798 | 799 | def updateProfilepic(self) -> bool: 800 | payload = {"image": helpers.utils.get_random_pfp()} 801 | headers = { 802 | "X-B3-TraceId": helpers.twitter.trace_id(), 803 | "Host": "api.twitter.com", 804 | "Timezone": "", 805 | "X-Twitter-Client-Language": "en", 806 | "X-Twitter-Client-Limit-Ad-Tracking": "0", 807 | "Accept-Language": "en", 808 | "User-Agent": self.user_agent, 809 | "kdt": self.auth['kdt'], 810 | "Content-Type": "application/x-www-form-urlencoded", 811 | "X-Client-UUID": self.uuid, 812 | "X-Twitter-Client-DeviceID": self.device_id, 813 | "X-Twitter-Client": "Twitter-iPhone", 814 | "Accept": "application/json", 815 | "Authorization": helpers.oauth.getAuth("POST","https://api.twitter.com/1.1/onboarding/task.json",self.auth["oauth_secret"],self.auth["oauth_token"],payload), 816 | "X-Twitter-API-Version": "5", 817 | "X-Twitter-Active-User": "yes", 818 | "X-Twitter-Client-Version": self.client_version 819 | } 820 | 821 | response = self.session.post( 822 | "https://api.twitter.com/1.1/account/update_profile_image.json", 823 | headers=headers, 824 | data=payload, 825 | ) 826 | if response.status_code == 200: 827 | LOGGER.debug("[+] Updated Profile pic") 828 | return response.status_code == 200 829 | 830 | def get_token(self) -> str: 831 | url = "https://api-31-0-0.twitter.com/1.1/account/settings.json?include_alt_text_compose=true&include_ext_dm_nsfw_media_filter=true&include_ext_re_upload_address_book_time=true&include_ext_sharing_audiospaces_listening_data_with_followers=true&include_ext_sso_connections=true&include_mention_filter=true&include_nsfw_admin_flag=true&include_nsfw_user_flag=true&include_universal_quality_filtering=true&protected=false" 832 | 833 | headers = { 834 | "host": "api-31-0-0.twitter.com", 835 | "kdt": self.auth["kdt"], 836 | "user-agent": self.user_agent, 837 | "x-twitter-client": "Twitter-iPhone", 838 | "x-twitter-client-deviceid": self.device_id, 839 | "x-twitter-active-user": "yes", 840 | "twitter-display-size": "1170x2532", 841 | "x-twitter-client-vendorid": self.vendor_id, 842 | "system-user-agent": self.system_user_agent, 843 | "x-twitter-client-version": "9.34.1", 844 | "x-twitter-client-limit-ad-tracking": "0", 845 | "x-b3-traceid": helpers.twitter.trace_id(), 846 | "accept-language": "en", 847 | "timezone": "", 848 | "authorization": helpers.oauth.getAuth( 849 | "POST", 850 | url, 851 | self.auth["oauth_secret"], 852 | self.auth["oauth_token"], 853 | "NO_VALUE", 854 | ), 855 | "x-twitter-client-language": "en", 856 | "x-client-uuid": self.uuid, 857 | "x-twitter-api-version": "5", 858 | "accept": "application/json", 859 | "content-type": "application/json", 860 | "os-version": "14.1", 861 | } 862 | r = self.session.post(url, headers=headers) 863 | url = "https://twitter.com/account/authenticate_web_view?redirect_url=https%3A%2F%2Fhelp.twitter.com%2F" 864 | 865 | headers = { 866 | "host": "twitter.com", 867 | "kdt": self.auth["kdt"], 868 | "user-agent": self.user_agent, 869 | "x-twitter-client": "Twitter-iPhone", 870 | "x-twitter-client-deviceid": self.device_id, 871 | "x-twitter-active-user": "yes", 872 | "twitter-display-size": self.display_size, 873 | "x-twitter-client-vendorid": self.vendor_id, 874 | "system-user-agent": self.system_user_agent, 875 | "x-twitter-client-version": self.client_version, 876 | "x-twitter-client-limit-ad-tracking": "0", 877 | "x-b3-traceid": helpers.twitter.trace_id(), 878 | "accept-language": "en", 879 | "timezone": "", 880 | "authorization": helpers.oauth.getAuth( 881 | "GET", 882 | url, 883 | self.auth["oauth_secret"], 884 | self.auth["oauth_token"], 885 | "NO_VALUE", 886 | ), 887 | "x-twitter-client-language": "en", 888 | "x-client-uuid": self.uuid, 889 | "x-twitter-api-version": "5", 890 | "accept": "application/json", 891 | "content-type": "application/json", 892 | "os-version": self.os_version, 893 | } 894 | r = self.session.get(url, headers=headers) 895 | return r.cookies["auth_token"] 896 | 897 | 898 | class TwitterGenerator: 899 | def __init__(self) -> None: 900 | self.lock = Lock() 901 | self.SessionManager = helpers.twitter.SessionManager(helpers.utils.proxies) 902 | if not os.path.exists("output"): 903 | os.mkdir("output") 904 | 905 | def save_token(self, token: str, path: str = None) -> None: 906 | if path is None: 907 | path = "output/tokens.txt" 908 | with self.lock: 909 | with open(path, "a", encoding="utf-8") as file: 910 | file.write(f"{token}\n") 911 | 912 | def gen(self): 913 | while True: 914 | try: 915 | twitter = TwitterSession() 916 | init_token = twitter.init_flow_token() 917 | LOGGER.debug("[+] Initiated signup flow") 918 | provider = random.choice(ENABLED_SOLVERS) 919 | captcha_key = provider.solve_captcha() 920 | LOGGER.info( 921 | f"[+] Solved Captcha: {captcha_key[:12]} - Solver used: {provider.name}" 922 | ) 923 | with KOPEECHKA.rent_email() as (activation_id, email): 924 | LOGGER.debug(f"[+] Rented email {email}") 925 | sent_otp = twitter.send_email_otp(email, init_token) 926 | if not sent_otp: 927 | LOGGER.error("[!] Failed to send email OTP") 928 | LOGGER.debug(f"[+] Sent_otp: {sent_otp}") 929 | email_code = KOPEECHKA.get_code(activation_id) 930 | if not email_code: 931 | LOGGER.error("[!] Failed to get email code, canceling email") 932 | KOPEECHKA.cancel_email(activation_id) 933 | continue 934 | LOGGER.info(f"[+] Got email code: {email_code}") 935 | js_instrumentation = helpers.twitter.get_web_instrumentation() 936 | LOGGER.debug(f"[+] JS Data: {str(js_instrumentation)[:12]}") 937 | second_token = twitter.email_code_flow( 938 | email, email_code, init_token, js_instrumentation, captcha_key 939 | ) 940 | LOGGER.debug("[+] Completed email flow") 941 | third_token = twitter.password_flow( 942 | second_token, helpers.utils.config.account_password 943 | ) 944 | LOGGER.debug("[+] Completed password flow") 945 | twitter.avatar_flow(third_token) 946 | LOGGER.debug("[+] Completed Avatar flow") 947 | auth_token = twitter.get_token() 948 | LOGGER.info(f"[+] Created account [{auth_token}]") 949 | session = self.SessionManager.init_session(auth_token) 950 | LOGGER.debug(f"[+] Initiated session Using [{auth_token}]") 951 | self.save_token( 952 | f"{email}:{helpers.utils.config.account_password}:{session.cookies.get('ct0', '')}:{auth_token}" 953 | ) 954 | if helpers.utils.config.use_pfp: 955 | self.SessionManager.set_pfp(session, helpers.utils.random_pfp_fiile()) 956 | except KeyboardInterrupt: 957 | LOGGER.debug("[+] Exiting...") 958 | break 959 | except: 960 | continue 961 | 962 | 963 | if __name__ == "__main__": 964 | Generator = TwitterGenerator() 965 | for i in range(helpers.utils.config.threads): 966 | Thread(target=Generator.gen).start() 967 | -------------------------------------------------------------------------------- /output/tokens.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozguryilmaz07/TwitterAccountGenerator/d0f61129f47755dc29770010e92ae47826b3df21/output/tokens.txt -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | colorlog 2 | httpx[http2] 3 | oauthlib 4 | requests_oauthlib 5 | attrs --------------------------------------------------------------------------------