Skip to content

Instantly share code, notes, and snippets.

@cptmacp
Last active February 14, 2026 17:38
Show Gist options
  • Select an option

  • Save cptmacp/1e9a9f20f69c113a0828fea8d13cb34c to your computer and use it in GitHub Desktop.

Select an option

Save cptmacp/1e9a9f20f69c113a0828fea8d13cb34c to your computer and use it in GitHub Desktop.
automate for skport endfield daily login claim via js script and send notification to discord channel
/** Config Starts. **/
const profiles = [
{
cred: "xxxxxxxxxxxxxxxxxxxxxx", // Replace with your Endfield cred cookie value ( get from cookie )
skGameRole: "xxxxxxxxxxxx", // Replace with your Endfield skGameRole cookie value ( get from cookie )
platform: "3",
vName: "1.0.0",
accountName: "acc_name" // Replace with a name to identify this account( a simple identifier )
}
// Add more profiles if needed
];
const discord_notify = true;
const myDiscordID = "xxxxxxxxxxxxxxxxxxx"; // Replace with your Discord ID (optional, for pinging)
const discordWebhook = "https://xxxx.discord.com/api/webhooks/xxxxxxxxxxx"; // Replace with your Discord webhook URL
/** Config ends. **/
const attendanceUrl = 'https://zonai.skport.com/web/v1/game/endfield/attendance';
async function main() {
const results = await Promise.all(profiles.map(autoClaimFunction));
if (discord_notify && discordWebhook) {
postWebhook(results);
}
}
function autoClaimFunction({ cred, skGameRole, platform, vName, accountName }) {
console.log(`[${accountName}] Checking credentials and performing check-in...`);
const timestamp = Math.floor(Date.now() / 1000).toString();
// Attempt to refresh token used for signing. If refresh fails, token will be empty.
let token = "";
try {
token = refreshToken(cred, platform, vName);
console.log(`[${accountName}] Token refreshed successfully.`);
} catch (e) {
console.error(`[${accountName}] Token refresh failed: ${e.message}`);
// proceed with empty token; API may reject if token required
}
const sign = generateSign('/web/v1/game/endfield/attendance', '', timestamp, token, platform, vName);
const header = {
'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',
'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'
};
const options = {
method: 'POST',
headers: header,
muteHttpExceptions: true,
};
let result = {
name: accountName,
success: false,
status: "",
rewards: ""
};
try {
const endfieldResponse = UrlFetchApp.fetch(attendanceUrl, options);
const responseJson = JSON.parse(endfieldResponse.getContentText());
console.log(`[${accountName}] API Response Code: ${responseJson.code}`);
if (responseJson.code === 0) {
result.success = true;
result.status = "✅ Check-in Successful";
if (responseJson.data && responseJson.data.awardIds) {
const awards = responseJson.data.awardIds.map(award => {
const resource = responseJson.data.resourceInfoMap ? responseJson.data.resourceInfoMap[award.id] : null;
return resource ? `${resource.name} x${resource.count}` : (award.id || "Unknown Item");
}).join('\n');
result.rewards = awards;
} else {
result.rewards = "No detailed reward info.";
}
} else if (responseJson.code === 10001) {
result.success = true;
result.status = "👌 Already Checked In";
result.rewards = "Nothing to claim";
} else {
result.success = false;
result.status = `❌ Error (Code: ${responseJson.code})`;
result.rewards = responseJson.message || "Unknown Error";
}
} catch (error) {
result.success = false;
result.status = "💥 Exception";
result.rewards = error.message;
console.error(`[${accountName}] Exception: ${error.message}`);
}
return result;
}
function postWebhook(results) {
console.log('Posting to Discord webhook...');
const allSuccess = results.every(r => r.success);
const hasError = !allSuccess;
const embedColor = allSuccess ? 5763719 : 15548997; // Green or Red
const fields = results.map(r => {
return {
name: `👤 ${r.name}`,
value: `**Status:** ${r.status}\n**Rewards:**\n${r.rewards ? r.rewards : 'None'}`,
inline: true
};
});
const payload = {
username: "Endfield Assistant",
avatar_url: "https://pbs.twimg.com/profile_images/1984225639407529984/2_3-HRTS_400x400.jpg",
embeds: [{
title: "📡 Endfield Daily Check-in Report",
color: embedColor,
fields: fields,
footer: {
text: `Time: ${new Date().toLocaleString('en-US', { timeZone: 'UTC' })} (UTC)`,
icon_url: "https://assets.skport.com/assets/favicon.ico"
}
}]
};
if (hasError && myDiscordID) {
payload.content = `<@${myDiscordID}> Script encountered an error, please check logs!`;
}
const options = {
method: 'POST',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
UrlFetchApp.fetch(discordWebhook, options);
} catch (e) {
console.error("Failed to send Discord webhook: " + e.message);
}
}
/** Helper: Refresh token used for signing **/
function refreshToken(cred, platform, vName) {
const refreshUrl = 'https://zonai.skport.com/web/v1/auth/refresh';
const header = {
'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/'
};
const options = {
method: 'GET',
headers: header,
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(refreshUrl, options);
const json = JSON.parse(response.getContentText());
if (json.code === 0 && json.data && json.data.token) {
return json.data.token;
} else {
throw new Error(`Refresh Failed (Code: ${json.code}, Msg: ${json.message})`);
}
}
/** Signature generation (HMAC-SHA256 then MD5) **/
function generateSign(path, body, timestamp, token, platform, vName) {
let str = path + body + timestamp;
const headerJson = `{"platform":"${platform}","timestamp":"${timestamp}","dId":"","vName":"${vName}"}`;
str += headerJson;
const hmacBytes = Utilities.computeHmacSha256Signature(str, token || '');
const hmacHex = bytesToHex(hmacBytes);
const md5Bytes = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, hmacHex);
return bytesToHex(md5Bytes);
}
function bytesToHex(bytes) {
return bytes.map(function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
}
@SutouOAO
Copy link

SutouOAO commented Feb 3, 2026

I've already claimed today's rewards, so I couldn't test the unclaimed scenario. I have only tested the script within script google.

This helps a lot, I appreciate it.

@cptmacp
Copy link
Author

cptmacp commented Feb 3, 2026

@HHim8826

Thanks for the info, Wondering how you figured out the combination for the sign hashing logic used by the website.
Anyways thanks for your effort.

I've updated the script from using your code snippet as a reference, and also took some nice points related to Discord webhook and message layout.

Tested on both Telegram + Discord with multiple accounts in profiles array.

@HHim8826
Copy link

HHim8826 commented Feb 3, 2026

I first identified the wrapper function we within the call stack, which led me to the core signing function oe.
image
Setting breakpoints, I was able to inspect the variable values and deduce the hashing logic (HMAC-SHA256 + MD5).
image

@cptmacp
Copy link
Author

cptmacp commented Feb 4, 2026

I first identified the wrapper function we within the call stack, which led me to the core signing function oe. image Setting breakpoints, I was able to inspect the variable values and deduce the hashing logic (HMAC-SHA256 + MD5). image

Awesome! Thanks for your insight and the effort.

@DragooNick
Copy link

DragooNick commented Feb 4, 2026

@cptmacp thanks for the script. <3
Do you happen to know what to change so the name in the discord message would be a user ping?
Before I could just change the variable of username to "<@" + myDiscordID + ">.
But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.

image But it should be like this,, if possible. :D image

@Ciberr2
Copy link

Ciberr2 commented Feb 4, 2026

* You will see  `cred` and `skGameRole`
image

I can't get skGameRole , in fact I don't even have any cookie that follows the "Platform_UserID_Server" format. That tampersmonkey script also doesn't work for me @cptmacp .

@cptmacp
Copy link
Author

cptmacp commented Feb 4, 2026

* You will see  `cred` and `skGameRole`
image

I can't get skGameRole , in fact I don't even have any cookie that follows the "Platform_UserID_Server" format. That tampersmonkey script also doesn't work for me @cptmacp .

did you enable, "Allow userscript"

image image image

After installing just open the link "https://game.skport.com/endfield/sign-in?header=0&hg_media=skport&hg_link_campaign=tools"

and you should see the popup on top right side

@Ciberr2
Copy link

Ciberr2 commented Feb 4, 2026

did you enable, "Allow userscript"

After installing just open the link "https://game.skport.com/endfield/sign-in?header=0&hg_media=skport&hg_link_campaign=tools"

and you should see the popup on top right side

Seems like it fixed itself after reinstalling the script.

@cptmacp
Copy link
Author

cptmacp commented Feb 4, 2026

@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to "<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.

image But it should be like this,, if possible. :D image

Hey, the ping will only happen in case of

https://gist.github.com/cptmacp/1e9a9f20f69c113a0828fea8d13cb34c#file-endfield_discord-js-L149

hasError is populated, it wont ping in normal scenario.

image

@itreecoke-del
Copy link

@cptmacp thanks for the script. <3 Do you happen to know what to change so the name in the discord message would be a user ping? Before I could just change the variable of username to "<@" + myDiscordID + ">. But I cant figure it out where/how to change it in the updated version. :) As it just gets out as plain text instead of the ping in Discord.

I can send what I looked up to change the message back to the old written text instead of the new layout since I preferred the old one.
1000019687

@MadAssEngineer
Copy link

@cptmacp Thanks for sharing!

I can send what I looked up to change the message back to the old written text instead of the new layout since I preferred the old one. 1000019687

I would really appreciate if u could share me exactly where and what changes u have made to the original script. I've tried to alter it on my end too but no luck, it just doesn't gives me the desired output 😫
P.S. don't have much experience of working with scripts.

@swablueme
Copy link

image it would be nice if this functionality could be added to maa end though ;-;

@itreecoke-del
Copy link

itreecoke-del commented Feb 7, 2026

@cptmacp Thanks for sharing!

I can send what I looked up to change the message back to the old written text instead of the new layout since I preferred the old one. 1000019687

I would really appreciate if u could share me exactly where and what changes u have made to the original script. I've tried to alter it on my end too but no luck, it just doesn't gives me the desired output 😫 P.S. don't have much experience of working with scripts.

Unsure what I specifically changed since I used a bit of ChatGPT and the previous script to try and figure things out. I don't want to flood the chat here either with the entirety of the script. Found an online notepad to copy and paste everything I changed.

https://anotepad.com/notes/jehek92a

Personal changes you could do to it since I changed it from Endfield Assistant to Supervisor Perlica
131 - Text for mention
138 - Username
139 - Avatar

@MadAssEngineer
Copy link

Unsure what I specifically changed since I used a bit of ChatGPT and the previous script to try and figure things out. I don't want to flood the chat here either with the entirety of the script. Found an online notepad to copy and paste everything I changed.

https://anotepad.com/notes/jehek92a

Personal changes you could do to it since I changed it from Endfield Assistant to Supervisor Perlica 131 - Text for mention 138 - Username 139 - Avatar

@itreecoke-del tysm 👐

@udaymanish6
Copy link

Why is the reward display
IMG_7051
bugged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment