Automated token refresh worker that logs into GameHub every 4 hours using OTP authentication and stores fresh tokens in Cloudflare KV storage.
- 🔄 Automatic Refresh: Runs every 4 hours via Cloudflare Cron Triggers
- 📧 Email-based OTP: Uses Mail.tm temporary email to receive verification codes
- 🔐 Signature Generation: Implements GameHub's MD5-based signature algorithm
- 💾 KV Storage: Stores tokens with metadata for easy retrieval
- 🔒 Secure Access: Protected endpoint with secret header authentication
- 🔍 Manual Refresh: HTTP endpoint for on-demand token refresh
⏰ Cron Trigger (every 4 hours)
↓
📧 Authenticate with Mail.tm API
↓
📨 Request OTP from GameHub (/ems/send)
↓
⏳ Wait 5 seconds for email
↓
📬 Fetch OTP from Mail.tm inbox
↓
🔐 Generate signature: MD5(sorted_params + secret_key)
↓
🔓 Login to GameHub (/email/login)
↓
💾 Store token in KV storage
↓
✅ Token ready for use
Secret Key: See SignUtils.smali in decompiled APK (search for the secret key constant)
Process:
- Collect parameters:
{captcha, clientparams, email, time} - Sort alphabetically by key
- Join as:
key1=value1&key2=value2&key3=value3 - Append secret:
&[SECRET_KEY_FROM_SMALI] - MD5 hash and convert to lowercase
Example:
// Input parameters
{
captcha: "123456",
clientparams: "5.1.0|16|en|...",
email: "[email protected]",
time: "1760030250000"
}
// After sorting and joining
"captcha=123456&clientparams=5.1.0|16|en|...&[email protected]&time=1760030250000&[SECRET_KEY]"
// MD5 hash (lowercase)
"[generated_signature_hash]"cd gamehub-token-refresher
npm installnpx wrangler kv:namespace create TOKEN_STORECopy the namespace ID and update wrangler.toml:
[[kv_namespaces]]
binding = "TOKEN_STORE"
id = "your_namespace_id_here"Edit wrangler.toml and update these values:
[vars]
GAMEHUB_EMAIL = "[email protected]"
GAMEHUB_API_BASE = "https://landscape-api.vgabc.com"
MAILTM_EMAIL = "[email protected]"
MAILTM_PASSWORD = "your-mailtm-password"
MAILTM_API_BASE = "https://api.mail.tm"
GAMEHUB_CLIENTPARAMS = "5.1.0|16|en|DEVICE_MODEL|WIDTH * HEIGHT|gamehub_android|gamehub_android_Official|MANUFACTURER|||||||||BENCHMARK_APP||CHIPSET"
GAMEHUB_SECRET_KEY = "[EXTRACT_FROM_SignUtils.smali]"Setting up Mail.tm:
- Visit https://mail.tm
- Create a temporary email account
- Note the email and password
- Use these in
MAILTM_EMAILandMAILTM_PASSWORD - Register the same email with GameHub
npm run deploycurl -X POST https://gamehub-token-refresher.YOUR_SUBDOMAIN.workers.dev/refreshRetrieve the current stored token (protected endpoint)
Authentication: Requires X-Worker-Auth: gamehub-internal-token-fetch-2025 header
Example (from another Cloudflare Worker):
const tokenResponse = await fetch(
'https://gamehub-token-refresher.emuready.workers.dev/token',
{
headers: {
'X-Worker-Auth': 'gamehub-internal-token-fetch-2025',
},
},
)
const tokenData = await tokenResponse.json()
console.log(tokenData.token) // "f589a94e-fec5-4aea-a96b-115ecdfd50d8"Response:
{
"token": "f589a94e-fec5-4aea-a96b-115ecdfd50d8",
"refreshed_at": "2025-10-09T17:42:35.509Z",
"expires_at": "2025-10-10T17:42:35.509Z"
}Security:
- ✅ Requests with correct header → Token returned
- ❌ Requests without header →
fuck you(403 Forbidden) - ❌ Requests from browsers →
fuck you(403 Forbidden)
Manually trigger a token refresh (bypasses cron)
Example:
curl -X POST https://gamehub-token-refresher.emuready.workers.dev/refreshResponse:
{
"success": true,
"token": "f589a94e-fec5-4aea-a96b-115ecdfd50d8",
"refreshed_at": "2025-10-09T18:00:00.000Z"
}Use Cases:
- Testing the token refresh flow
- Debugging authentication issues
- Immediate token refresh needed
Service info and status
Response:
GameHub Token Refresher
Endpoints:
GET /token - Get current token (protected)
POST /refresh - Manually refresh token
Key: gamehub_token
Value:
{
"token": "f589a94e-fec5-4aea-a96b-115ecdfd50d8",
"refreshed_at": "2025-10-09T17:42:35.509Z",
"expires_at": "2025-10-10T17:42:35.509Z"
}Storage Type: Persistent (no expiration)
Access: Remote production KV namespace
[triggers]
crons = ["0 */4 * * *"] # Every 4 hours at the top of the hourSchedule:
- 00:00 UTC
- 04:00 UTC
- 08:00 UTC
- 12:00 UTC
- 16:00 UTC
- 20:00 UTC
Token Lifetime: ~24 hours (estimated) Safety Margin: Refreshes 6 times within token lifetime
The main GameHub API worker fetches tokens from this service:
// Fetch real token from token-refresher worker
const tokenResponse = await fetch(`${env.TOKEN_REFRESHER_URL}/token`, {
headers: {
'X-Worker-Auth': 'gamehub-internal-token-fetch-2025',
},
})
if (tokenResponse.ok) {
const tokenData = await tokenResponse.json()
const realToken = tokenData.token
// Replace fake-token with real token
bodyJson.token = realToken
// Regenerate signature
bodyJson.sign = generateSignature(bodyJson)
}npm run tailVisit Cloudflare Dashboard:
- Go to Workers & Pages
- Select
gamehub-token-refresher - Click Triggers tab
- View cron execution history
# List all keys
npx wrangler kv:key list --binding=TOKEN_STORE --remote
# Get token value
npx wrangler kv:key get gamehub_token --binding=TOKEN_STORE --remote# Without auth header (should get "fuck you")
curl https://gamehub-token-refresher.emuready.workers.dev/token
# With auth header (should get token)
curl -H "X-Worker-Auth: gamehub-internal-token-fetch-2025" \
https://gamehub-token-refresher.emuready.workers.dev/token| Error | Action | Recovery |
|---|---|---|
| Mail.tm auth fails | Throw error | Retry on next cron (4 hours) |
| OTP not received | Throw error | Retry on next cron |
| Invalid OTP | Throw error | Retry on next cron |
| Login fails | Throw error | Retry on next cron |
| Network timeout | Automatic retry | Cloudflare handles retry |
All errors are logged to Cloudflare dashboard for debugging
- Cold Start: ~200ms
- Execution Time: ~6-8 seconds (including 5s sleep for OTP)
- Memory: <10MB
- Cost: Free tier (< 100k requests/day)
- Check Mail.tm inbox manually at https://mail.tm
- Increase sleep time in
src/index.js:await sleep(10000) // 10 seconds instead of 5
- Check GameHub email is registered with Mail.tm account
- Verify secret key matches the one in
SignUtils.smalifrom the decompiled APK - Check parameters are sorted alphabetically
- Ensure timestamp is in milliseconds (not seconds)
- Test with known working example
- Check Cloudflare dashboard > Workers > Triggers
- Verify cron syntax in
wrangler.toml - Manually trigger via
POST /refresh - Review worker logs for errors
- Check namespace ID matches
wrangler.toml - Use
--remoteflag when checking KV:npx wrangler kv:key get gamehub_token --binding=TOKEN_STORE --remote
- Manually trigger refresh to populate KV
This is normal! It means the security is working. Only the gamehub-api worker with the correct auth header can access tokens.
- Secret Key: Extract from
SignUtils.smaliin decompiled APK (reverse engineering required) - Email Credentials: Stored as environment variables in
wrangler.toml - Token Storage: KV is private to worker, not publicly accessible
- API Access:
/tokenendpoint protected by secret header - Auth Header: Custom auth header required (configure in worker code)
Run locally (with remote KV):
npm run devTest refresh locally:
curl -X POST http://localhost:8787/refresh- Retry Logic: Exponential backoff for OTP fetch failures
- Multiple Accounts: Support token rotation across multiple Mail.tm accounts
- Token Validation: Verify token works before storing
- Notification: Alert on consecutive failures (email/webhook)
- Rate Limiting: Prevent abuse of manual refresh endpoint
- Metrics: Track success rate and latency
- Tokens expire after ~24 hours
- Refresh runs 6 times within token lifetime (4-hour intervals)
- Mail.tm is a free temporary email service (no registration needed)
- GameHub API uses MD5 signatures for authentication
- Secret key was reverse-engineered from
SignUtils.smaliin APK - Worker uses service-to-service authentication (not user-facing)