from aiohttp import ( ClientResponseError, ClientSession, ClientTimeout, BasicAuth ) from aiohttp_socks import ProxyConnector from base64 import urlsafe_b64decode from datetime import datetime from colorama import * import asyncio, time, json, pytz, re, os wib = pytz.timezone('Asia/Jakarta') class Interlink: def __init__(self) -> None: self.HEADERS = { "Accept-Encoding": "*/*", "User-Agent": "okhttp/4.12.0", "Accept-Encoding": "gzip" } self.BASE_API = "https://prod.interlinklabs.ai/api/v1" self.proxies = [] self.proxy_index = 0 self.account_proxies = {} self.access_tokens = {} def clear_terminal(self): os.system('cls' if os.name == 'nt' else 'clear') def log(self, message): print( f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}{message}", flush=True ) def welcome(self): print( f""" {Fore.GREEN + Style.BRIGHT}Auto Claim {Fore.BLUE + Style.BRIGHT}Interlink - BOT """ f""" {Fore.GREEN + Style.BRIGHT}Rey? {Fore.YELLOW + Style.BRIGHT} """ ) def format_seconds(self, seconds): hours, remainder = divmod(seconds, 3600) minutes, seconds = divmod(remainder, 60) return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}" def load_accounts(self): filename = "tokens.json" env_tokens = os.getenv("TOKENS_JSON") if env_tokens: try: data = json.loads(env_tokens) if isinstance(data, list): self.log( f"{Fore.GREEN + Style.BRIGHT}Loaded accounts from environment variable TOKENS_JSON.{Style.RESET_ALL}" ) return data self.log( f"{Fore.RED + Style.BRIGHT}TOKENS_JSON is not a JSON array. No accounts loaded.{Style.RESET_ALL}" ) return [] except json.JSONDecodeError as exc: self.log( f"{Fore.RED + Style.BRIGHT}Failed to parse TOKENS_JSON: {exc}.{Style.RESET_ALL}" ) return [] try: if not os.path.exists(filename): self.log(f"{Fore.RED}File {filename} Not Found.{Style.RESET_ALL}") return [] with open(filename, 'r') as file: data = json.load(file) if isinstance(data, list): return data self.log( f"{Fore.RED + Style.BRIGHT}{filename} does not contain a JSON array. No accounts loaded.{Style.RESET_ALL}" ) return [] except json.JSONDecodeError as exc: self.log( f"{Fore.RED + Style.BRIGHT}Failed to parse {filename}: {exc}.{Style.RESET_ALL}" ) return [] async def load_proxies(self): filename = "proxy.txt" try: env_proxies = os.getenv("PROXIES") if env_proxies: self.proxies = self.parse_env_list(env_proxies) source = "environment variable PROXIES" else: if not os.path.exists(filename): self.log(f"{Fore.RED + Style.BRIGHT}File {filename} Not Found.{Style.RESET_ALL}") return with open(filename, 'r') as f: self.proxies = [line.strip() for line in f.read().splitlines() if line.strip()] source = filename if not self.proxies: self.log(f"{Fore.RED + Style.BRIGHT}No Proxies Found.{Style.RESET_ALL}") return self.log( f"{Fore.GREEN + Style.BRIGHT}Proxies Total : {Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT}{len(self.proxies)}{Style.RESET_ALL}" f"{Fore.GREEN + Style.BRIGHT} (from {source}){Style.RESET_ALL}" ) except Exception as e: self.log(f"{Fore.RED + Style.BRIGHT}Failed To Load Proxies: {e}{Style.RESET_ALL}") self.proxies = [] def check_proxy_schemes(self, proxies): schemes = ["http://", "https://", "socks4://", "socks5://"] if any(proxies.startswith(scheme) for scheme in schemes): return proxies return f"http://{proxies}" def get_next_proxy_for_account(self, account): if account not in self.account_proxies: if not self.proxies: return None proxy = self.check_proxy_schemes(self.proxies[self.proxy_index]) self.account_proxies[account] = proxy self.proxy_index = (self.proxy_index + 1) % len(self.proxies) return self.account_proxies[account] def rotate_proxy_for_account(self, account): if not self.proxies: return None proxy = self.check_proxy_schemes(self.proxies[self.proxy_index]) self.account_proxies[account] = proxy self.proxy_index = (self.proxy_index + 1) % len(self.proxies) return proxy def build_proxy_config(self, proxy=None): if not proxy: return None, None, None if proxy.startswith("socks"): connector = ProxyConnector.from_url(proxy) return connector, None, None elif proxy.startswith("http"): match = re.match(r"http://(.*?):(.*?)@(.*)", proxy) if match: username, password, host_port = match.groups() clean_url = f"http://{host_port}" auth = BasicAuth(username, password) return None, clean_url, auth else: return None, proxy, None raise Exception("Unsupported Proxy Type.") def decode_token(self, token: str): try: header, payload, signature = token.split(".") decoded_payload = urlsafe_b64decode(payload + "==").decode("utf-8") parsed_payload = json.loads(decoded_payload) exp_time = parsed_payload["exp"] return exp_time except Exception as e: return None def mask_account(self, account): if "@" in account: local, domain = account.split('@', 1) mask_account = local[:3] + '*' * 3 + local[-3:] return f"{mask_account}@{domain}" def parse_env_list(self, raw: str): items = [] if not raw: return items normalized = raw.replace("\r\n", "\n") for line in normalized.split("\n"): for part in line.split(","): candidate = part.strip() if candidate: items.append(candidate) return items def get_env_bool(self, name: str, default=None): value = os.getenv(name) if value is None: return default value = value.strip().lower() if value in {"1", "true", "yes", "y"}: return True if value in {"0", "false", "no", "n"}: return False return default def print_question(self): while True: try: print(f"{Fore.WHITE + Style.BRIGHT}1. Run With Proxy{Style.RESET_ALL}") print(f"{Fore.WHITE + Style.BRIGHT}2. Run Without Proxy{Style.RESET_ALL}") proxy_choice = int(input(f"{Fore.BLUE + Style.BRIGHT}Choose [1/2] -> {Style.RESET_ALL}").strip()) if proxy_choice in [1, 2]: proxy_type = ( "With" if proxy_choice == 1 else "Without" ) print(f"{Fore.GREEN + Style.BRIGHT}Run {proxy_type} Proxy Selected.{Style.RESET_ALL}") break else: print(f"{Fore.RED + Style.BRIGHT}Please enter either 1 or 2.{Style.RESET_ALL}") except ValueError: print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter a number (1 or 2).{Style.RESET_ALL}") rotate_proxy = False if proxy_choice == 1: while True: rotate_proxy = input(f"{Fore.BLUE + Style.BRIGHT}Rotate Invalid Proxy? [y/n] -> {Style.RESET_ALL}").strip() if rotate_proxy in ["y", "n"]: rotate_proxy = rotate_proxy == "y" break else: print(f"{Fore.RED + Style.BRIGHT}Invalid input. Enter 'y' or 'n'.{Style.RESET_ALL}") return proxy_choice, rotate_proxy async def check_connection(self, proxy_url=None): connector, proxy, proxy_auth = self.build_proxy_config(proxy_url) try: async with ClientSession(connector=connector, timeout=ClientTimeout(total=10)) as session: async with session.get(url="https://api.ipify.org?format=json", proxy=proxy, proxy_auth=proxy_auth) as response: response.raise_for_status() return True except (Exception, ClientResponseError) as e: self.log( f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} Connection Not 200 OK {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}" ) return None async def token_balance(self, email: str, proxy_url=None, retries=5): url = f"{self.BASE_API}/token/get-token" headers = { **self.HEADERS, "Authorization": f"Bearer {self.access_tokens[email]}" } await asyncio.sleep(3) for attempt in range(retries): connector, proxy, proxy_auth = self.build_proxy_config(proxy_url) try: async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response: response.raise_for_status() return await response.json() except (Exception, ClientResponseError) as e: if attempt < retries - 1: await asyncio.sleep(5) continue self.log( f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} GET Token Earned Failed {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}" ) return None async def claimable_check(self, email: str, proxy_url=None, retries=5): url = f"{self.BASE_API}/token/check-is-claimable" headers = { **self.HEADERS, "Authorization": f"Bearer {self.access_tokens[email]}" } await asyncio.sleep(3) for attempt in range(retries): connector, proxy, proxy_auth = self.build_proxy_config(proxy_url) try: async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: async with session.get(url=url, headers=headers, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response: response.raise_for_status() return await response.json() except (Exception, ClientResponseError) as e: if attempt < retries - 1: await asyncio.sleep(5) continue self.log( f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} GET Status Failed {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}" ) return None async def claim_airdrop(self, email: str, proxy_url=None, retries=1): url = f"{self.BASE_API}/token/claim-airdrop" headers = { **self.HEADERS, "Authorization": f"Bearer {self.access_tokens[email]}", "Content-Length": "2", "Content-Type": "application/json" } await asyncio.sleep(3) for attempt in range(retries): connector, proxy, proxy_auth = self.build_proxy_config(proxy_url) try: async with ClientSession(connector=connector, timeout=ClientTimeout(total=60)) as session: async with session.post(url=url, headers=headers, json={}, proxy=proxy, proxy_auth=proxy_auth, ssl=False) as response: response.raise_for_status() return await response.json() except (Exception, ClientResponseError) as e: if attempt < retries - 1: await asyncio.sleep(5) continue self.log( f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} Not Claimed {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.YELLOW+Style.BRIGHT} {str(e)} {Style.RESET_ALL}" ) return None async def process_check_connection(self, email: str, use_proxy: bool, rotate_proxy: bool): while True: proxy = self.get_next_proxy_for_account(email) if use_proxy else None self.log( f"{Fore.CYAN+Style.BRIGHT}Proxy :{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {proxy if proxy else 'No Proxy'} {Style.RESET_ALL}" ) is_valid = await self.check_connection(proxy) if is_valid: return True if rotate_proxy: proxy = self.rotate_proxy_for_account(email) await asyncio.sleep(1) continue return False async def process_accounts(self, email: str, use_proxy: bool, rotate_proxy: bool): is_valid = await self.process_check_connection(email, use_proxy, rotate_proxy) if not is_valid: return proxy = self.get_next_proxy_for_account(email) if use_proxy else None balance = await self.token_balance(email, proxy) if balance: token_balance = balance.get("data", {}).get("interlinkTokenAmount", 0) silver_balance = balance.get("data", {}).get("interlinkSilverTokenAmount", 0) gold_balance = balance.get("data", {}).get("interlinkGoldTokenAmount", 0) diamond_balance = balance.get("data", {}).get("interlinkDiamondTokenAmount", 0) self.log(f"{Fore.CYAN+Style.BRIGHT}Balance:{Style.RESET_ALL}") self.log( f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}" f"{Fore.BLUE+Style.BRIGHT}Interlink:{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {token_balance} {Style.RESET_ALL}" ) self.log( f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}" f"{Fore.BLUE+Style.BRIGHT}Silver :{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {silver_balance} {Style.RESET_ALL}" ) self.log( f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}" f"{Fore.BLUE+Style.BRIGHT}Gold :{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {gold_balance} {Style.RESET_ALL}" ) self.log( f"{Fore.MAGENTA+Style.BRIGHT} ● {Style.RESET_ALL}" f"{Fore.BLUE+Style.BRIGHT}Diamond :{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {diamond_balance} {Style.RESET_ALL}" ) claimable = await self.claimable_check(email, proxy) if claimable: is_claimable = claimable.get("data", {}).get("isClaimable", False) if is_claimable: claim = await self.claim_airdrop(email, proxy) if claim: reward = claim.get("data") or "N/A" self.log( f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}" f"{Fore.GREEN+Style.BRIGHT} Claimed Successfully {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.CYAN+Style.BRIGHT} Reward: {Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT}{reward}{Style.RESET_ALL}" ) else: next_frame_ts = claimable.get("data", {}).get("nextFrame", 0) / 1000 next_frame_wib = datetime.fromtimestamp(next_frame_ts).astimezone(wib).strftime('%x %X %Z') self.log( f"{Fore.CYAN+Style.BRIGHT}Mining :{Style.RESET_ALL}" f"{Fore.YELLOW+Style.BRIGHT} Already Claimed {Style.RESET_ALL}" f"{Fore.MAGENTA+Style.BRIGHT}-{Style.RESET_ALL}" f"{Fore.CYAN+Style.BRIGHT} Next Claim at: {Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT}{next_frame_wib}{Style.RESET_ALL}" ) async def main(self): try: accounts = self.load_accounts() if not accounts: self.log(f"{Fore.RED}No Accounts Loaded.{Style.RESET_ALL}") return env_use_proxy = self.get_env_bool("USE_PROXY") env_rotate_proxy = self.get_env_bool("ROTATE_PROXY") if env_use_proxy is None: proxy_choice, rotate_proxy = self.print_question() use_proxy = proxy_choice == 1 else: use_proxy = bool(env_use_proxy) rotate_proxy = use_proxy and ( env_rotate_proxy if env_rotate_proxy is not None else True ) mode_text = "With Proxy" if use_proxy else "Without Proxy" source_text = "environment variables" self.log( f"{Fore.GREEN + Style.BRIGHT}Run {mode_text} Selected via {source_text}.{Style.RESET_ALL}" ) if not use_proxy: rotate_proxy = False elif rotate_proxy: self.log( f"{Fore.GREEN + Style.BRIGHT}Invalid proxy auto-rotation enabled.{Style.RESET_ALL}" ) else: self.log( f"{Fore.YELLOW + Style.BRIGHT}Invalid proxy auto-rotation disabled.{Style.RESET_ALL}" ) while True: self.clear_terminal() self.welcome() self.log( f"{Fore.GREEN + Style.BRIGHT}Account's Total: {Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT}{len(accounts)}{Style.RESET_ALL}" ) if use_proxy: await self.load_proxies() separator = "=" * 27 for idx, account in enumerate(accounts, start=1): if account: email = account["email"] token = account["token"] self.log( f"{Fore.CYAN + Style.BRIGHT}{separator}[{Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT} {idx} {Style.RESET_ALL}" f"{Fore.CYAN + Style.BRIGHT}Of{Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT} {len(accounts)} {Style.RESET_ALL}" f"{Fore.CYAN + Style.BRIGHT}]{separator}{Style.RESET_ALL}" ) if not "@" in email or not token: self.log( f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} Invalid Account Data {Style.RESET_ALL}" ) continue self.log( f"{Fore.CYAN+Style.BRIGHT}Account:{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {self.mask_account(email)} {Style.RESET_ALL}" ) exp_time = self.decode_token(token) if not exp_time: self.log( f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} Invalid Token {Style.RESET_ALL}" ) continue if int(time.time()) > exp_time: self.log( f"{Fore.CYAN+Style.BRIGHT}Status :{Style.RESET_ALL}" f"{Fore.RED+Style.BRIGHT} Token Already Expired {Style.RESET_ALL}" ) continue self.access_tokens[email] = token await self.process_accounts(email, use_proxy, rotate_proxy) await asyncio.sleep(3) self.log(f"{Fore.CYAN + Style.BRIGHT}={Style.RESET_ALL}"*65) seconds = 4 * 60 * 60 while seconds > 0: formatted_time = self.format_seconds(seconds) print( f"{Fore.CYAN+Style.BRIGHT}[ Wait for{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} {formatted_time} {Style.RESET_ALL}" f"{Fore.CYAN+Style.BRIGHT}... ]{Style.RESET_ALL}" f"{Fore.WHITE+Style.BRIGHT} | {Style.RESET_ALL}" f"{Fore.BLUE+Style.BRIGHT}All Accounts Have Been Processed...{Style.RESET_ALL}", end="\r" ) await asyncio.sleep(1) seconds -= 1 except Exception as e: self.log(f"{Fore.RED+Style.BRIGHT}Error: {e}{Style.RESET_ALL}") raise e if __name__ == "__main__": try: bot = Interlink() asyncio.run(bot.main()) except KeyboardInterrupt: print( f"{Fore.CYAN + Style.BRIGHT}[ {datetime.now().astimezone(wib).strftime('%x %X %Z')} ]{Style.RESET_ALL}" f"{Fore.WHITE + Style.BRIGHT} | {Style.RESET_ALL}" f"{Fore.RED + Style.BRIGHT}[ EXIT ] Interlink - BOT{Style.RESET_ALL} " )