Skip to content

Instantly share code, notes, and snippets.

@BitTheByte
Last active August 22, 2023 17:58
Show Gist options
  • Select an option

  • Save BitTheByte/88437dbb3e751aa1dc9b66401d45ccba to your computer and use it in GitHub Desktop.

Select an option

Save BitTheByte/88437dbb3e751aa1dc9b66401d45ccba to your computer and use it in GitHub Desktop.

Revisions

  1. BitTheByte revised this gist Apr 27, 2020. 1 changed file with 60 additions and 58 deletions.
    118 changes: 60 additions & 58 deletions twitter-tweet.py
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    # -*- coding: utf-8 -*-

    from base64 import b64decode,b64encode
    from urllib.parse import quote,parse_qs,urlsplit
    from urllib.parse import quote,parse_qs,urlsplit,urlparse
    from random import randint
    from bs4 import BeautifulSoup
    import calendar
    @@ -19,15 +19,12 @@ def __init__(self):
    self.session = requests.Session()
    self.access_token = None
    self.guest_token = None
    self.has_challenge = False
    self.challenged = False
    self.challenge_type = None
    self.challenge = None
    self.on_challenge = None
    self.xauth = None

    def login(self,username,password):
    self.xauth = self.xauth_login(username,password)

    def oauth_signature(self,request,oauth_secret):
    key = bytes(self.twitter_android_secret +"&"+ oauth_secret, 'UTF-8')
    message = bytes(request, 'UTF-8')
    @@ -69,29 +66,59 @@ def xauth_login(self,username,password):
    "ui_metrics":""
    }).json()

    if "login_verification_request_type" in auth.keys():
    self.challenge = auth
    return self.solve_challenge(auth)
    self.xauth = auth
    if "login_verification_request_url" in auth.keys():
    self.challenged = True
    self.challenge = auth
    self.challenge_type = parse_qs(urlparse(auth["login_verification_request_url"]).query)['challenge_type'][0]
    return auth

    def solve_challenge(self,xauth):
    self.has_challenge = True
    def challenge_access_token(self,user_id,request_id):
    oauth_nonce = ''.join([str(randint(0,9)) for n in range(31)])
    oauth_timestamp = str(calendar.timegm(time.gmtime()))
    challenge = xauth["login_verification_request_url"]
    request_id = xauth["login_verification_request_id"]
    response = self.session.get(challenge)

    return self.session.post("https://api.twitter.com/oauth/access_token",data={
    "x_auth_mode":"client_auth",
    "x_auth_login_verification":"1",
    "x_auth_login_challenge": "1",
    "send_error_codes":"true",
    "login_verification_user_id": user_id,
    "login_verification_request_id": request_id
    },
    headers = {
    "Authorization":'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="HMAC-SHA1"'.format(
    oauth_nonce = oauth_nonce,
    oauth_timestamp = oauth_timestamp,
    oauth_consumer_key = self.twitter_android_key,
    oauth_signature = self.signature_message(url="https://api.twitter.com/oauth/access_token",params={
    "login_verification_request_id": request_id,
    "login_verification_user_id": user_id,
    "oauth_consumer_key":self.twitter_android_key,
    "oauth_nonce": oauth_nonce,
    "oauth_signature_method":"HMAC-SHA1",
    "oauth_timestamp": oauth_timestamp,
    "oauth_version":"1.0",
    "send_error_codes":"true",
    "x_auth_login_challenge":"1",
    "x_auth_login_verification":"1",
    "x_auth_mode":"client_auth",
    },oauth_secret="")
    ),
    "Content-Type": "application/x-www-form-urlencoded",
    "Accept": "application/json",
    }).json()

    def solve_challenge(self,challenge,answer):
    self.has_challenge = True
    challenge_url = challenge["login_verification_request_url"]
    request_id = challenge["login_verification_request_id"]
    response = self.session.get(challenge_url)
    soup = BeautifulSoup(response.content, "lxml")
    authenticity_token = soup.select_one("input[name=authenticity_token]")["value"]
    challenge_id = soup.select_one("input[name=challenge_id]")["value"]
    user_id = soup.select_one("input[name=user_id]")["value"]
    self.challenge_type = soup.select_one("input[name=challenge_type]")["value"]

    if type(self.on_challenge) == types.FunctionType:
    challenge_response = self.on_challenge(self.challenge_type)
    else:
    challenge_response = input("[%s] Challenge Answer: " % self.challenge_type)

    data = {
    'authenticity_token':authenticity_token,
    'challenge_id':challenge_id,
    @@ -100,40 +127,13 @@ def solve_challenge(self,xauth):
    'platform':'mobile',
    'redirect_after_login':'',
    'remember_me':'true',
    'challenge_response':challenge_response,
    'challenge_response':answer,
    }
    self.session.post("https://twitter.com/account/login_challenge",data=data)

    return self.session.post("https://api.twitter.com/oauth/access_token",data={
    "x_auth_mode":"client_auth",
    "x_auth_login_verification":"1",
    "x_auth_login_challenge": "1",
    "send_error_codes":"true",
    "login_verification_user_id": user_id,
    "login_verification_request_id": request_id
    },
    headers = {
    "Authorization":'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="HMAC-SHA1"'.format(
    oauth_nonce = oauth_nonce,
    oauth_timestamp = oauth_timestamp,
    oauth_consumer_key = self.twitter_android_key,
    oauth_signature = self.signature_message(url="https://api.twitter.com/oauth/access_token",params={
    "login_verification_request_id": request_id,
    "login_verification_user_id": user_id,
    "oauth_consumer_key":self.twitter_android_key,
    "oauth_nonce": oauth_nonce,
    "oauth_signature_method":"HMAC-SHA1",
    "oauth_timestamp": oauth_timestamp,
    "oauth_version":"1.0",
    "send_error_codes":"true",
    "x_auth_login_challenge":"1",
    "x_auth_login_verification":"1",
    "x_auth_mode":"client_auth",
    },oauth_secret="")
    ),
    "Content-Type": "application/x-www-form-urlencoded",
    "Accept": "application/json",
    }).json()
    twitter_session = self.challenge_access_token(user_id, request_id)
    self.xauth = twitter_session
    return twitter_session


    def auth_headers(self,oauth_nonce,oauth_timestamp,oauth_signature,skip_token=False):
    @@ -186,9 +186,9 @@ def tweet(self, text):
    oauth_nonce= oauth_nonce,
    oauth_timestamp= oauth_timestamp,
    oauth_signature= self.signature_message(
    url = api_statuses,
    params = params,
    oauth_secret = self.xauth['oauth_token_secret']
    url= api_statuses,
    params= params,
    oauth_secret= self.xauth['oauth_token_secret']
    )
    )

    @@ -197,9 +197,11 @@ def tweet(self, text):
    return self.session.post(api_statuses,headers=headers,data=post_params.encode('utf-8'),verify=False).json()


    t = Twitter()
    t.on_challenge = lambda type: "j75285eh"
    if t.has_challenge:
    print(t.challenge_type, t.challenge, t.xauth)
    t.login("[email protected]","password")
    t.tweet("Hello from python!")
    api = Twitter()
    result = api.xauth_login("username","password")

    if api.challenged:
    answer = input("code:").strip()
    api.solve_challenge(result,answer)

    api.tweet("XXXXXXXXXXXXXXXXXXXXX")
  2. BitTheByte created this gist Apr 27, 2020.
    205 changes: 205 additions & 0 deletions twitter-tweet.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,205 @@
    # -*- coding: utf-8 -*-

    from base64 import b64decode,b64encode
    from urllib.parse import quote,parse_qs,urlsplit
    from random import randint
    from bs4 import BeautifulSoup
    import calendar
    import requests
    import hashlib
    import base64
    import time
    import hmac
    import types

    class Twitter(object):
    def __init__(self):
    self.twitter_android_secret = "Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys"
    self.twitter_android_key = "3nVuSoBZnx6U4vzUxf5w"
    self.session = requests.Session()
    self.access_token = None
    self.guest_token = None
    self.has_challenge = False
    self.challenge_type = None
    self.challenge = None
    self.on_challenge = None
    self.xauth = None

    def login(self,username,password):
    self.xauth = self.xauth_login(username,password)

    def oauth_signature(self,request,oauth_secret):
    key = bytes(self.twitter_android_secret +"&"+ oauth_secret, 'UTF-8')
    message = bytes(request, 'UTF-8')
    digester = hmac.new(key, message, hashlib.sha1)
    signature1 = digester.digest()
    signature2 = base64.urlsafe_b64encode(signature1)
    signature2 = str(signature2, 'UTF-8').replace("-","+").replace("_","/")
    return quote(signature2,safe='')

    def signature_message(self,url,params,oauth_secret,method="POST"):
    header = method + "&" + quote(url,safe='') + "&"
    body = bytes()
    for key,value in params.items():
    body += bytes(key,"UTF-8") + b"=" + bytes(value,"UTF-8") + b"&"
    body = body[:-1]
    return self.oauth_signature(header + quote(body,safe=''),oauth_secret)

    def xauth_login(self,username,password):
    self.access_token = self.session.post("https://api.twitter.com/oauth2/token",params = {'grant_type':'client_credentials'},
    headers = {
    "Accept": "application/json",
    "Authorization": "Basic " + b64encode((self.twitter_android_key + ":" + self.twitter_android_secret).encode("utf8")).decode("utf8")
    }
    ).json()["access_token"]

    self.guest_token = self.session.post("https://api.twitter.com/1.1/guest/activate.json",headers={"Authorization": "Bearer " + self.access_token}).json()["guest_token"]

    auth = self.session.post("https://api.twitter.com/auth/1/xauth_password.json",headers={
    "Authorization": "Bearer " + self.access_token,
    "X-Guest-Token": self.guest_token
    },
    params = {
    "x_auth_identifier":username,
    "x_auth_password":password,
    "send_error_codes":"true",
    "x_auth_login_challenge":"1",
    "x_auth_login_verification":"1",
    "x_auth_country_code":"US",
    "ui_metrics":""
    }).json()

    if "login_verification_request_type" in auth.keys():
    self.challenge = auth
    return self.solve_challenge(auth)
    return auth

    def solve_challenge(self,xauth):
    self.has_challenge = True
    oauth_nonce = ''.join([str(randint(0,9)) for n in range(31)])
    oauth_timestamp = str(calendar.timegm(time.gmtime()))
    challenge = xauth["login_verification_request_url"]
    request_id = xauth["login_verification_request_id"]
    response = self.session.get(challenge)
    soup = BeautifulSoup(response.content, "lxml")
    authenticity_token = soup.select_one("input[name=authenticity_token]")["value"]
    challenge_id = soup.select_one("input[name=challenge_id]")["value"]
    user_id = soup.select_one("input[name=user_id]")["value"]
    self.challenge_type = soup.select_one("input[name=challenge_type]")["value"]

    if type(self.on_challenge) == types.FunctionType:
    challenge_response = self.on_challenge(self.challenge_type)
    else:
    challenge_response = input("[%s] Challenge Answer: " % self.challenge_type)

    data = {
    'authenticity_token':authenticity_token,
    'challenge_id':challenge_id,
    'user_id':user_id,
    'challenge_type':self.challenge_type,
    'platform':'mobile',
    'redirect_after_login':'',
    'remember_me':'true',
    'challenge_response':challenge_response,
    }
    self.session.post("https://twitter.com/account/login_challenge",data=data)

    return self.session.post("https://api.twitter.com/oauth/access_token",data={
    "x_auth_mode":"client_auth",
    "x_auth_login_verification":"1",
    "x_auth_login_challenge": "1",
    "send_error_codes":"true",
    "login_verification_user_id": user_id,
    "login_verification_request_id": request_id
    },
    headers = {
    "Authorization":'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="HMAC-SHA1"'.format(
    oauth_nonce = oauth_nonce,
    oauth_timestamp = oauth_timestamp,
    oauth_consumer_key = self.twitter_android_key,
    oauth_signature = self.signature_message(url="https://api.twitter.com/oauth/access_token",params={
    "login_verification_request_id": request_id,
    "login_verification_user_id": user_id,
    "oauth_consumer_key":self.twitter_android_key,
    "oauth_nonce": oauth_nonce,
    "oauth_signature_method":"HMAC-SHA1",
    "oauth_timestamp": oauth_timestamp,
    "oauth_version":"1.0",
    "send_error_codes":"true",
    "x_auth_login_challenge":"1",
    "x_auth_login_verification":"1",
    "x_auth_mode":"client_auth",
    },oauth_secret="")
    ),
    "Content-Type": "application/x-www-form-urlencoded",
    "Accept": "application/json",
    }).json()


    def auth_headers(self,oauth_nonce,oauth_timestamp,oauth_signature,skip_token=False):
    return {
    "Authorization": 'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_token="{oauth_token}", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="{oauth_signature_method}"'.format(
    oauth_token = self.xauth["oauth_token"] if not skip_token else "",
    oauth_nonce = oauth_nonce,
    oauth_timestamp = oauth_timestamp,
    oauth_signature = oauth_signature,
    oauth_consumer_key = self.twitter_android_key,
    oauth_signature_method = "HMAC-SHA1"
    ),
    "User-Agent": "TwitterAndroid/8.40.0-release.02 (18400002-r-2) Nexus 7/7.0 (asus;Nexus 7;google;nakasi;0;;0;2012)",
    "X-Twitter-Active-User": "yes",
    "X-Twitter-API-Version": "5",
    "X-Twitter-Client": "TwitterAndroid",
    "X-Twitter-Client-Language": "en-US",
    "Accept": "application/json",
    }

    def tweet(self, text):
    api_statuses = "https://api.twitter.com/1.1/statuses/update.json"
    oauth_nonce = ''.join([str(randint(0,9)) for n in range(31)])
    oauth_timestamp = str(calendar.timegm(time.gmtime()))

    params = {
    "batch_mode":"off",
    "cards_platform":"Android-12",
    "earned_read":"true",
    "enable_dm_commands":"false",
    "ext":"mediaRestrictions%2CaltText%2CmediaStats%2CmediaColor%2Cinfo360%2CcameraMoment%2ChighlightedLabel%2Cmaster_playlist_only",
    "include_blocked_by":"true",
    "include_blocking":"true",
    "include_cards":"true",
    "include_entities":"true",
    "include_media_features":"true",
    "include_reply_count":"true",
    "oauth_consumer_key":self.twitter_android_key,
    "oauth_nonce": oauth_nonce,
    "oauth_signature_method":"HMAC-SHA1",
    "oauth_timestamp":oauth_timestamp,
    "oauth_token": self.xauth["oauth_token"],
    "oauth_version":"1.0",
    "send_error_codes":"true",
    "status": quote(text,safe=''),
    "tweet_mode":"extended"
    }

    headers = self.auth_headers(
    oauth_nonce= oauth_nonce,
    oauth_timestamp= oauth_timestamp,
    oauth_signature= self.signature_message(
    url = api_statuses,
    params = params,
    oauth_secret = self.xauth['oauth_token_secret']
    )
    )

    headers["Content-Type"] = "application/x-www-form-urlencoded"
    post_params = '&'.join([k + u"=" + v for k,v in params.items()])
    return self.session.post(api_statuses,headers=headers,data=post_params.encode('utf-8'),verify=False).json()


    t = Twitter()
    t.on_challenge = lambda type: "j75285eh"
    if t.has_challenge:
    print(t.challenge_type, t.challenge, t.xauth)
    t.login("[email protected]","password")
    t.tweet("Hello from python!")