Last active
July 25, 2025 03:52
-
-
Save 2shrestha22/3b0f76c37c1775f7b9ec693461b7aa82 to your computer and use it in GitHub Desktop.
Request bootloader unlock for Xiaomi devices
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import subprocess | |
| import sys | |
| import os | |
| # Configuration | |
| FEED_TIME_SHIFT = 1400 # Time shift in milliseconds - adjust this value as needed | |
| # Server lists | |
| ntp_servers = [ | |
| "ntp0.ntp-servers.net", "ntp1.ntp-servers.net", "ntp2.ntp-servers.net", | |
| "ntp3.ntp-servers.net", "ntp4.ntp-servers.net", "ntp5.ntp-servers.net", | |
| "ntp6.ntp-servers.net" | |
| ] | |
| MI_SERVERS = ['161.117.96.161', '20.157.18.26'] | |
| # Installation of dependencies | |
| def install_package(package): | |
| subprocess.check_call([sys.executable, "-m", "pip", "install", package]) | |
| required_packages = ["requests", "ntplib", "pytz", "urllib3", "linecache"] | |
| for package in required_packages: | |
| try: | |
| __import__(package) | |
| except ImportError: | |
| print(f"Installing package {package}...") | |
| install_package(package) | |
| os.system('cls' if os.name == 'nt' else 'clear') | |
| import hashlib | |
| import random | |
| import time | |
| from datetime import datetime, timezone, timedelta | |
| import ntplib | |
| import pytz | |
| import urllib3 | |
| import json | |
| # Version | |
| os.system('cls' if os.name == 'nt' else 'clear') | |
| scriptversion = "ARU_FHL_v070425" | |
| # Global variables | |
| print(f"{scriptversion}") | |
| print(f"\nChecking account status") | |
| token = open("token.txt").read().strip().split()[0] | |
| cookie_value = token | |
| feed_time_shift = FEED_TIME_SHIFT | |
| feed_time_shift_1 = feed_time_shift / 1000 | |
| # Generates a unique device identifier | |
| def generate_device_id(): | |
| random_data = f"{random.random()}-{time.time()}" | |
| device_id = hashlib.sha1(random_data.encode('utf-8')).hexdigest().upper() | |
| return device_id | |
| # Get the current Beijing time from NTP | |
| def get_initial_beijing_time(): | |
| client = ntplib.NTPClient() | |
| beijing_tz = pytz.timezone("Asia/Shanghai") | |
| for server in ntp_servers: | |
| try: | |
| print(f"\nGetting current Beijing time") | |
| response = client.request(server, version=3) | |
| ntp_time = datetime.fromtimestamp(response.tx_time, timezone.utc) | |
| beijing_time = ntp_time.astimezone(beijing_tz) | |
| print(f"[Beijing time]: {beijing_time.strftime('%Y-%m-%d %H:%M:%S.%f')}") | |
| return beijing_time | |
| except Exception as e: | |
| print(f"Error connecting to {server}: {e}") | |
| print(f"Could not connect to any NTP server.") | |
| return None | |
| # Synchronize Beijing time | |
| def get_synchronized_beijing_time(start_beijing_time, start_timestamp): | |
| elapsed = time.time() - start_timestamp | |
| current_time = start_beijing_time + timedelta(seconds=elapsed) | |
| return current_time | |
| # Wait until the target time taking into account the ping | |
| def wait_until_target_time(start_beijing_time, start_timestamp): | |
| next_day = start_beijing_time + timedelta(days=1) | |
| print(f"\nBootloader unlock request") | |
| print(f"[Set offset]: {feed_time_shift:.2f} ms.") | |
| target_time = next_day.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(seconds=feed_time_shift_1) | |
| print(f"[Waiting until]: {target_time.strftime('%Y-%m-%d %H:%M:%S.%f')}") | |
| print(f"\nDo not close this window...") | |
| while True: | |
| current_time = get_synchronized_beijing_time(start_beijing_time, start_timestamp) | |
| time_diff = target_time - current_time | |
| if time_diff.total_seconds() > 1: | |
| time.sleep(min(1.0, time_diff.total_seconds() - 1)) | |
| elif current_time >= target_time: | |
| print(f"Target time reached: {current_time.strftime('%Y-%m-%d %H:%M:%S.%f')}. Starting to send requests...") | |
| break | |
| else: | |
| time.sleep(0.0001) | |
| # Check if account unlocking is possible via API | |
| def check_unlock_status(session, cookie_value, device_id): | |
| try: | |
| url = "https://sgp-api.buy.mi.com/bbs/api/global/user/bl-switch/state" | |
| headers = { | |
| "Cookie": f"new_bbs_serviceToken={cookie_value};versionCode=500411;versionName=5.4.11;deviceId={device_id};" | |
| } | |
| response = session.make_request('GET', url, headers=headers) | |
| if response is None: | |
| print(f"[Error] Could not get unlock status.") | |
| return False | |
| response_data = json.loads(response.data.decode('utf-8')) | |
| response.release_conn() | |
| if response_data.get("code") == 100004: | |
| print(f"[Error] Cookie has expired, needs to be updated.") | |
| input(f"Press Enter to close...") | |
| exit() | |
| data = response_data.get("data", {}) | |
| is_pass = data.get("is_pass") | |
| button_state = data.get("button_state") | |
| deadline_format = data.get("deadline_format", "") | |
| if is_pass == 4: | |
| if button_state == 1: | |
| print(f"[Account status]: request can be sent.") | |
| return True | |
| elif button_state == 2: | |
| print(f"[Account status]: request block until {deadline_format} (Month/Day).") | |
| status_2 = (input(f"Continue (Yes/No)?: ") ) | |
| if (status_2 == 'y' or status_2 == 'Y' or status_2 == 'yes' or status_2 == 'Yes' or status_2 == 'YES'): | |
| return True | |
| else: | |
| input(f"Press Enter to close...") | |
| exit() | |
| elif button_state == 3: | |
| print(f"[Account status]: account was created less than 30 days ago.") | |
| status_3 = (input(f"Continue (Yes/No)?: ") ) | |
| if (status_3 == 'y' or status_3 == 'Y' or status_3 == 'yes' or status_3 == 'Yes' or status_3 == 'YES'): | |
| return True | |
| else: | |
| input(f"Press Enter to close...") | |
| exit() | |
| elif is_pass == 1: | |
| print(f"[Account status]: request was approved, unlock is possible until {deadline_format}.") | |
| input(f"Press Enter to close...") | |
| exit() | |
| else: | |
| print(f"[Account status]: unknown status.") | |
| input(f"Press Enter to close...") | |
| exit() | |
| except Exception as e: | |
| print(f"[Status check error] {e}") | |
| return False | |
| # Container for working with HTTP requests | |
| class HTTP11Session: | |
| def __init__(self): | |
| self.http = urllib3.PoolManager( | |
| maxsize=10, | |
| retries=True, | |
| timeout=urllib3.Timeout(connect=2.0, read=15.0), | |
| headers={} | |
| ) | |
| def make_request(self, method, url, headers=None, body=None): | |
| try: | |
| request_headers = {} | |
| if headers: | |
| request_headers.update(headers) | |
| request_headers['Content-Type'] = 'application/json; charset=utf-8' | |
| if method == 'POST': | |
| if body is None: | |
| body = '{"is_retry":true}'.encode('utf-8') | |
| request_headers['Content-Length'] = str(len(body)) | |
| request_headers['Accept-Encoding'] = 'gzip, deflate, br' | |
| request_headers['User-Agent'] = 'okhttp/4.12.0' | |
| request_headers['Connection'] = 'keep-alive' | |
| response = self.http.request( | |
| method, | |
| url, | |
| headers=request_headers, | |
| body=body, | |
| preload_content=False | |
| ) | |
| return response | |
| except Exception as e: | |
| print(f"[Network error] {e}") | |
| return None | |
| def main(): | |
| device_id = generate_device_id() | |
| session = HTTP11Session() | |
| if check_unlock_status(session, cookie_value, device_id): | |
| start_beijing_time = get_initial_beijing_time() | |
| if start_beijing_time is None: | |
| print(f"Could not establish initial time. Press Enter to close...") | |
| input() | |
| exit() | |
| start_timestamp = time.time() | |
| wait_until_target_time(start_beijing_time, start_timestamp) | |
| url = "https://sgp-api.buy.mi.com/bbs/api/global/apply/bl-auth" | |
| headers = { | |
| "Cookie": f"new_bbs_serviceToken={cookie_value};versionCode=500411;versionName=5.4.11;deviceId={device_id};" | |
| } | |
| try: | |
| while True: | |
| request_time = get_synchronized_beijing_time(start_beijing_time, start_timestamp) | |
| print(f"[Request]: Sending request at {request_time.strftime('%Y-%m-%d %H:%M:%S.%f')} (UTC+8)") | |
| response = session.make_request('POST', url, headers=headers) | |
| if response is None: | |
| continue | |
| response_time = get_synchronized_beijing_time(start_beijing_time, start_timestamp) | |
| print(f"[Response]: Response received at {response_time.strftime('%Y-%m-%d %H:%M:%S.%f')} (UTC+8)") | |
| try: | |
| response_data = response.data | |
| response.release_conn() | |
| json_response = json.loads(response_data.decode('utf-8')) | |
| code = json_response.get("code") | |
| data = json_response.get("data", {}) | |
| if code == 0: | |
| apply_result = data.get("apply_result") | |
| if apply_result == 1: | |
| print(f"[Status]: Request was approved, checking status...") | |
| check_unlock_status(session, cookie_value, device_id) | |
| elif apply_result == 3: | |
| deadline_format = data.get("deadline_format", "Not specified") | |
| print(f"[Status]: Request was not sent, limit reached. Try again on {deadline_format} (Month/Day).") | |
| input(f"Press Enter to close...") | |
| exit() | |
| elif apply_result == 4: | |
| deadline_format = data.get("deadline_format", "Not specified") | |
| print(f"[Status]: Request was not sent, block imposed until {deadline_format} (Month/Day).") | |
| input(f"Press Enter to close...") | |
| exit() | |
| elif code == 100001: | |
| print(f"[Status]: Request was rejected, error in the request.") | |
| print(f"[FULL RESPONSE]: {json_response}") | |
| elif code == 100003: | |
| print(f"[Status]: Request may have been approved, checking status...") | |
| print(f"[Full response]: {json_response}") | |
| check_unlock_status(session, cookie_value, device_id) | |
| elif code is not None: | |
| print(f"[Status]: Unknown request status: {code}") | |
| print(f"[Full response]: {json_response}") | |
| else: | |
| print(f"[Error]: Response does not contain required code.") | |
| print(f"[Full response]: {json_response}") | |
| except json.JSONDecodeError: | |
| print(f"[Error]: Could not decode JSON response.") | |
| print(f"[Server response]: {response_data}") | |
| except Exception as e: | |
| print(f"[Response processing error]: {e}") | |
| continue | |
| except Exception as e: | |
| print(f"[Request error]: {e}") | |
| input(f"Press Enter to close...") | |
| exit() | |
| if __name__ == "__main__": | |
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| replace_this_with_new_bbs_serviceToken_value |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script will help you to automate sending bootloader unlock request instead of using Xiaomi Community app which always gives quota limit reached error. Bootloader unlock is only allowed in Global ROMs
new_bbs_serviceTokenfrom cookies using Cookie Editortoken.txtto write downnew_bbs_serviceTokenpython3 bootloader-unlock-req.pyCredit: https://xdaforums.com/t/how-to-unlock-bootloader-on-xiaomi-hyperos-all-devices-except-cn.4654009/