Skip to content

Instantly share code, notes, and snippets.

@magnade
Last active March 9, 2026 23:33
Show Gist options
  • Select an option

  • Save magnade/8711a64f415a908fca882682c68d0582 to your computer and use it in GitHub Desktop.

Select an option

Save magnade/8711a64f415a908fca882682c68d0582 to your computer and use it in GitHub Desktop.
python script to automate skport endfield daily login claim
#!/usr/bin/env python3
"""
Endfield Daily Check-In Script
original: https://gist.github.com/cptmacp/70f66f2a4fb9d5fa708d33fbcc8e265a
this was converted from original by deepseek
Run locally with Python 3.6+ using only the standard library.
external json support and exit codes on error provided by StoneToad
"""
import json
import time
import hmac
import hashlib
import urllib.request
import urllib.error
from binascii import hexlify
import sys
# if set, load profiles from this file
#profiles_secrets_file = "endfield_secrets.json"
# ------------------- CONFIGURATION (edit these) -------------------
profiles = [
{
"cred": "xxxxxxxxxxxxxxxxxxxxxx", # Replace with your Endfield cred cookie
"skGameRole": "xxxxxxxxxxxx", # Replace with your Endfield skGameRole cookie
"platform": "3",
"vName": "1.0.0",
"accountName": "acc_name" # A simple identifier for this account
}
# Add more profiles if needed
]
telegram_notify = False
myTelegramID = "xxxxx" # Replace with your Telegram ID
telegramBotToken = "xxxxxx:xxxxxxxx" # Replace with your bot token
# -------------------------------------------------------------------
ATTENDANCE_URL = "https://zonai.skport.com/web/v1/game/endfield/attendance"
REFRESH_URL = "https://zonai.skport.com/web/v1/auth/refresh"
def bytes_to_hex(byte_data):
"""Convert bytes to a hexadecimal string."""
return hexlify(byte_data).decode('ascii')
def generate_sign(path, body, timestamp, token, platform, vName):
"""
Generate the required sign header.
Steps:
1. Concatenate: path + body + timestamp
2. Append header JSON: {"platform":p,"timestamp":t,"dId":"","vName":v}
3. HMAC‑SHA256 (key = token, message = the whole string)
4. Convert HMAC bytes to hex
5. MD5 of that hex string → final hex sign
"""
# Build the header JSON part
header_json = json.dumps({
"platform": platform,
"timestamp": timestamp,
"dId": "",
"vName": vName
}, separators=(',', ':')) # compact, no extra spaces
# The full string to be HMACed
data_to_sign = path + body + timestamp + header_json
# HMAC‑SHA256 using token (or empty string if token is None/empty)
key = token.encode('utf-8') if token else b''
hmac_bytes = hmac.new(key, data_to_sign.encode('utf-8'), hashlib.sha256).digest()
hmac_hex = bytes_to_hex(hmac_bytes)
# MD5 of the hex string (the string itself, not the raw bytes)
md5_hash = hashlib.md5(hmac_hex.encode('utf-8')).hexdigest()
return md5_hash
def refresh_token(cred, platform, vName):
"""
Call the refresh endpoint to obtain a fresh token.
Returns the token string, or raises an exception on failure.
"""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "application/json, text/plain, */*",
"cred": cred,
"platform": platform,
"vName": vName,
"Origin": "https://game.skport.com",
"Referer": "https://game.skport.com/"
}
req = urllib.request.Request(REFRESH_URL, headers=headers, method="GET")
try:
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read().decode('utf-8'))
if data.get("code") == 0 and data.get("data") and data["data"].get("token"):
return data["data"]["token"]
else:
raise Exception(f"Refresh failed: {data.get('message', 'unknown error')}")
except Exception as e:
raise Exception(f"Refresh request error: {e}")
def auto_claim(profile):
"""Perform the check‑in for one profile and return a result message."""
cred = profile["cred"]
skGameRole = profile["skGameRole"]
platform = profile["platform"]
vName = profile["vName"]
account_name = profile["accountName"]
print(f"[{account_name}] Starting check‑in...")
timestamp = str(int(time.time()))
# Try to refresh the token – if it fails we continue with an empty token
token = ""
try:
token = refresh_token(cred, platform, vName)
print(f"[{account_name}] Token refreshed successfully.")
except Exception as e:
print(f"[{account_name}] Token refresh failed: {e} (continuing with empty token)")
# Generate the sign
sign = generate_sign("/web/v1/game/endfield/attendance", "", timestamp, token, platform, vName)
# Prepare headers
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0",
"Accept": "*/*",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br, zstd", # urllib will handle decompression automatically
"Referer": "https://game.skport.com/",
"Content-Type": "application/json",
"sk-language": "en",
"sk-game-role": skGameRole,
"cred": cred,
"platform": platform,
"vName": vName,
"timestamp": timestamp,
"sign": sign,
"Origin": "https://game.skport.com",
"Connection": "keep-alive",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site"
}
req = urllib.request.Request(ATTENDANCE_URL, headers=headers, method="POST", data=None)
ok = True
message = f"Daily reward claim for {account_name}"
try:
try:
with urllib.request.urlopen(req, timeout=10) as resp:
response_status = resp.status
response_data = json.loads(resp.read().decode('utf-8'))
except urllib.error.HTTPError as e:
response_status = e.code
response_data = json.loads(e.read().decode('utf-8'))
code = response_data.get("code")
print(f"[{account_name}] API Response Code: {code}")
if code == 0:
message += "\nClaim successful!"
awards = []
for award in response_data.get("data", {}).get("awardIds", []):
resource = response_data["data"]["resourceInfoMap"].get(str(award["id"]), {})
awards.append(f"{resource.get('name', 'Unknown')}: {resource.get('count', '?')}")
if awards:
message += f"\nAwards: {', '.join(awards)}"
elif code == 10001:
message += "\nAlready claimed today."
else:
msg = response_data.get("message", "Unknown error")
message += f"\nError: {msg}"
ok = False
except Exception as e:
print(f"[{account_name}] Exception: {e}")
message += f"\nFailed to claim: {e}"
ok = False
return message, ok
def post_webhook(text):
"""Send a message via Telegram bot."""
print("Posting to Telegram...")
url = f"https://api.telegram.org/bot{telegramBotToken}/sendMessage"
payload = json.dumps({
"chat_id": myTelegramID,
"text": text,
"parse_mode": "HTML"
}).encode('utf-8')
headers = {
"Content-Type": "application/json",
"Content-Length": len(payload)
}
req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
try:
with urllib.request.urlopen(req, timeout=10) as resp:
# Just consume the response, no need to parse
resp.read()
except Exception as e:
print(f"Telegram notification failed: {e}")
def main():
global profiles_secrets_file, profiles
try:
if profiles_secrets_file:
with open(profiles_secrets_file, 'r') as file:
profiles = json.load(file)
except NameError:
print("profiles_secrets_file not defined using inline variable")
"""Run check‑in for all profiles and send a Telegram summary."""
messages = []
all_ok = True
for profile in profiles:
msg, this_ok = auto_claim(profile)
messages.append(msg)
all_ok = this_ok and all_ok
combined = "\n\n".join(messages)
if telegram_notify and telegramBotToken and myTelegramID:
post_webhook(combined)
# Also print to console
print("\n" + "="*40)
print(combined)
print("="*40)
if not all_ok:
sys.exit(1) # let systemd figure out that a failure happened
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment