I’m just going to release my TikTok X-Bogus Signer because I’m bored, and it was easy anyway. Here you go—some simple code with the signer that includes functions to get user information and retrieve all videos for a profile.
"""
TikTok X-Bogus Signer, made by github.com/cxstles (replit.com/@sky).
"""
from tls_client import Session, response
from urllib.parse import urlencode
from random import randint
from hashlib import md5
from time import time
import requests
class CustomTikTokApiClient:
"""
A custom TikTok API client for fetching user information and scraping videos.
Args:
user_agent (str, optional): The user agent to be used in HTTP requests. Default is a Chrome user agent.
Attributes:
user_agent (str): The user agent used in HTTP requests.
http_session (Session): An HTTP session object for making requests.
max_cursor (int): The maximum cursor value for video scraping.
Methods:
double_md5(string_to_hash: str) -> str:
Computes a double MD5 hash of the input string.
rc4_encrypt(plaintext: str, key: list[int]) -> str:
Encrypts plaintext using the RC4 algorithm with a given key.
base64_encode(string: str, key_table: str) -> str:
Encodes a string using base64 encoding.
filter(num_list: list[int]) -> list[int]:
Filters a list of integers based on a predefined pattern.
scramble(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) -> str:
Scrambles a set of characters based on a predefined pattern.
checksum(salt_list: str) -> int:
Computes a checksum for a list of values.
_x_bogus(params: str, user_agent: str, timestamp: int, data: str = "") -> str:
Generates an X-Bogus header value for TikTok API requests.
sign(params: str, ua: str) -> str:
Signs a set of parameters for TikTok API requests.
generate_params(extra: dict = {}, device_id: int = randint(7000000000000000000, 7999999999999999999)) -> str:
Generates a string of URL-encoded parameters for TikTok API requests.
generate_headers(extra: dict = {}) -> dict:
Generates a dictionary of HTTP headers for TikTok API requests.
fetch_user_info(username: str) -> response:
Fetches user information from TikTok API.
convert_to_sec_uid(username: str) -> str:
Converts a TikTok username to its corresponding secUid.
scrape_videos(username: str) -> response:
Scrapes TikTok videos from a user's profile.
"""
def __init__(self, user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'):
"""
Initialize a CustomTikTokApiClient.
Args:
user_agent (str, optional): The user agent to be used in HTTP requests. Default is a Chrome user agent.
"""
self.user_agent = user_agent
self.http_session = Session(client_identifier='chrome_109')
self.max_cursor = 0
@staticmethod
def double_md5(string_to_hash: str) -> str:
"""Compute a double MD5 hash of the input string."""
return md5(md5(string_to_hash.encode()).digest()).hexdigest()
@staticmethod
def rc4_encrypt(plaintext: str, key: list[int]) -> str:
"""Encrypt plaintext using the RC4 algorithm with a given key."""
s_box = [_ for _ in range(256)]
index = 0
for _ in range(256):
index = (index + s_box[_] + key[_ % len(key)]) % 256
s_box[_], s_box[index] = s_box[index], s_box[_]
_ = 0
index = 0
ciphertext = ""
for char in plaintext:
_ = (_ + 1) % 256
index = (index + s_box[_]) % 256
s_box[_], s_box[index] = s_box[index], s_box[_]
keystream = s_box[(s_box[_] + s_box[index]) % 256]
ciphertext += chr(ord(char) ^ keystream)
return ciphertext
@staticmethod
def base64_encode(string: str, key_table: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") -> str:
"""Encode a string using base64 encoding."""
last_list = list()
for i in range(0, len(string), 3):
try:
num_1 = ord(string[i])
num_2 = ord(string[i + 1])
num_3 = ord(string[i + 2])
arr_1 = num_1 >> 2
arr_2 = (3 & num_1) << 4 | (num_2 >> 4)
arr_3 = ((15 & num_2) << 2) | (num_3 >> 6)
arr_4 = 63 & num_3
except IndexError:
arr_1 = num_1 >> 2
arr_2 = ((3 & num_1) << 4) | 0
arr_3 = 64
arr_4 = 64
last_list.append(arr_1)
last_list.append(arr_2)
last_list.append(arr_3)
last_list.append(arr_4)
return "".join([key_table[value] for value in last_list])
@staticmethod
def filter(num_list: list[int]) -> list[int]:
"""Filter a list of integers based on a predefined pattern."""
return [
num_list[x - 1]
for x in [
3,
5,
7,
9,
11,
13,
15,
17,
19,
21,
4,
6,
8,
10,
12,
14,
16,
18,
20,
]
]
@staticmethod
def scramble(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s) -> str:
"""Scramble a set of characters based on a predefined pattern."""
return "".join(
[
chr(_)
for _ in [
a,
k,
b,
l,
c,
m,
d,
n,
e,
o,
f,
p,
g,
q,
h,
r,
i,
s,
j,
]
]
)
@staticmethod
def checksum(salt_list: str) -> int:
"""Compute a checksum for a list of values."""
checksum = 64
_ = [checksum := checksum ^ x for x in salt_list[3:]]
return checksum
@staticmethod
def _x_bogus(params: str, user_agent: str, timestamp: int, data: str = "") -> str:
"""Generate an X-Bogus header value for TikTok API requests."""
md5_data = CustomTikTokApiClient.double_md5(data)
md5_params = CustomTikTokApiClient.double_md5(params)
md5_ua = md5(
CustomTikTokApiClient.base64_encode(CustomTikTokApiClient.rc4_encrypt(user_agent, [0, 1, 14])).encode()
).hexdigest()
salt_list = [
timestamp,
536919696,
64,
0,
1,
14,
bytes.fromhex(md5_params)[-2],
bytes.fromhex(md5_params)[-1],
bytes.fromhex(md5_data)[-2],
bytes.fromhex(md5_data)[-1],
bytes.fromhex(md5_ua)[-2],
bytes.fromhex(md5_ua)[-1],
]
salt_list.extend([(timestamp >> i) & 0xFF for i in range(24, -1, -8)])
salt_list.extend([(salt_list[1] >> i) & 0xFF for i in range(24, -1, -8)])
salt_list.extend([CustomTikTokApiClient.checksum(salt_list), 255])
num_list = CustomTikTokApiClient.filter(salt_list)
rc4_num_list = CustomTikTokApiClient.rc4_encrypt(CustomTikTokApiClient.scramble(*num_list), [255])
return CustomTikTokApiClient.base64_encode(f"\x02ÿ{rc4_num_list}", "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe")
@staticmethod
def sign(params: str, ua: str) -> str:
"""Sign a set of parameters for TikTok API requests."""
return params + '&X-Bogus=' + CustomTikTokApiClient._x_bogus(params, ua, int(time()))
def generate_params(self, extra: dict = {}, device_id: int = randint(7000000000000000000, 7999999999999999999)) -> str:
"""
Generate a string of URL-encoded parameters for TikTok API requests.
Args:
extra (dict, optional): Additional parameters to include.
device_id (int, optional): The device ID. Default is a random 19-digit number.
Returns:
str: The URL-encoded parameter string.
"""
return urlencode({
**extra,
'aid': 1988,
'app_language': 'en',
'app_name': 'tiktok_web',
'battery_info': 1,
'browser_language': 'en',
'browser_name': 'Mozilla',
'browser_online': 'true',
'browser_platform': 'Win32',
'browser_version': self.user_agent,
'channel': 'tiktok_web',
'cookie_enabled': 'true',
'device_id': device_id,
'device_platform': 'web_pc',
'focus_state': 'true',
'from_page': 'user',
'history_len': '3',
'is_fullscreen': 'false',
'is_page_visible': 'true',
'os': 'windows',
'priority_region': 'US',
'referer': '',
'region': 'US',
'screen_height': '1080',
'screen_width': '1920',
'tz_name': 'Africa/Casablanca',
'webcast_language': 'en',
})
def generate_headers(self, extra: dict = {}) -> dict:
"""
Generate a dictionary of HTTP headers for TikTok API requests.
Args:
extra (dict, optional): Additional headers to include.
Returns:
dict: The HTTP headers.
"""
return {
**extra,
'authority': 'www.tiktok.com',
'accept': '*/*',
'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3',
'referer': 'https://www.tiktok.com/',
'sec-ch-ua': '"Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': self.user_agent
}
def fetch_user_info(self, username: str) -> response:
"""
Fetch user information from TikTok API.
Args:
username (str): The TikTok username or uniqueId.
Returns:
response: The HTTP response containing user information.
"""
params = self.generate_params({
'uniqueId': username
})
try:
response = self.http_session.get(f'https://www.tiktok.com/api/user/detail/?{self.sign(params, self.user_agent)}', headers=self.generate_headers())
return response
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return None
def convert_to_sec_uid(self, username: str):
"""
Convert a TikTok username to its corresponding secUid.
Args:
username (str): The TikTok username or uniqueId.
Returns:
str: The secUid of the user.
"""
user_info = self.fetch_user_info(username)
if user_info:
data = user_info.json()['userInfo'].get('user', {})
sec_uid = data.get('secUid', '')
return sec_uid
else:
return ''
def scrape_videos(self, username: str) -> response:
"""
Scrape TikTok videos from a user's profile.
Args:
username (str): The TikTok username or uniqueId.
Returns:
response: The HTTP response containing video information.
"""
sec_uid = self.convert_to_sec_uid(username)
if not sec_uid:
print(f"Failed to fetch secUid for {username}.")
return None
params = self.generate_params({
'secUid': sec_uid,
'id': sec_uid,
'type': 1,
'count': 30,
'minCursor': 0,
'maxCursor': self.max_cursor,
'shareUid': '',
'lang': '',
'verifyFp': '',
'region': 'US',
'priority_region': '',
'appId': 1233,
})
try:
response = self.http_session.get(f'https://www.tiktok.com/api/recommend/item_list/?{self.sign(params, self.user_agent)}', headers=self.generate_headers())
self.max_cursor = response.json().get('maxCursor', self.max_cursor)
return response
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return None
if __name__ == '__main__':
tiktok_client = CustomTikTokApiClient()
username = 'subwaysurfers'
user_info = tiktok_client.fetch_user_info(username)
if user_info:
print(f"User Info for {username}:")
print(user_info.json())
else:
print(f"Failed to fetch user info for {username}.")