Files
qinglong/脚本库/APP版/账密/享玩游戏APP/2025-04-28_sudojia_xiangwan_659341f6.js
2026-05-24 05:33:05 +00:00

343 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// # Source: https://github.com/sudojia/AutoTaskScript/blob/script/src/client/sudojia_xiangwan.js
// # Raw: https://raw.githubusercontent.com/sudojia/AutoTaskScript/script/src/client/sudojia_xiangwan.js
// # Repo: sudojia/AutoTaskScript
// # Path: src/client/sudojia_xiangwan.js
// # UploadedAt: 2025-04-28T19:26:13+08:00
// # SHA256: 659341f6d90da24ae84aff1ca890993bb08f62f22537ed7eca9ee139ad06e61d
// # Category: APP版/账密
// # Evidence: username/password/mobile/login
//
/**
* 享玩游戏APP
* 下载链接https://dl.duoyou.com/fenapk/xwshare/xw_100016.apk?version=1.3
*
* 会员v0起始签到 10 个玩豆,连续签到递增 1 玩豆,最高签到 15 个玩豆
* 会员v1-2起始 15最高 20
* ...
* 会员v10起始 75最高 80
* 具体自行查看签到规则
*
* 以会员v0来计算包含连签奖励
* 10 玩豆 兑换 0.1 现金,
* 500 玩豆 兑换 5 现金,大约需 21 天
* 1000 玩豆 兑换 10 现金,大约需 30 天
* 5000 玩豆 兑换 50 现金,大约需 200 天
* 10000 玩豆 兑换 100现金大约需 381 天
* 30000 玩豆 兑换 300 现金,大约需 1135 天 😂😂😂
*
* export XWGAME_ACCOUNTS = '手机号#密码'
* 多账号用 & 或换行
*
* @author Telegram@sudojia
* @site https://blog.imzjw.cn
* @date 2025/02/25
*
* const $ = new Env('享玩游戏APP')
* cron: 33 0 * * *
*/
const initScript = require('../utils/initScript')
const {$, notify, sudojia, checkUpdate} = initScript('享玩游戏APP');
const crypto = require('crypto');
const moment = require('moment');
const fs = require('fs').promises;
const path = require('path');
const xiangWanList = process.env.XWGAME_ACCOUNTS ? process.env.XWGAME_ACCOUNTS.split(/[\n&]/) : [];
// 消息推送
let message = '';
// token 缓存地址
const TOKEN_CACHE_PATH = path.join(__dirname, 'xiangwan_token_cache.json');
// 接口地址
const baseUrl = 'https://sdk-api.xiangwan.com'
// 加密秘钥Base64
const keyBase64 = '5snOI0E5WUpP99pG5+fzug==';
// 解码 Base64 得到原始的二进制密钥
const key = Buffer.from(keyBase64, 'base64');
// 加密 IvBase64
const ivBase64 = 'KhVRUtkYTNM82dSDxb7/YQ==';
// 解码 Base64 得到原始的二进制 IV
const iv = Buffer.from(ivBase64, 'base64');
// 请求头
const headers = {
'User-Agent': 'okhttp/4.11.0',
'Accept-Encoding': 'gzip',
'Content-Type': 'application/x-www-form-urlencoded'
};
!(async () => {
await checkUpdate($.name, xiangWanList);
for (let i = 0; i < xiangWanList.length; i++) {
const index = i + 1;
const [account, pwd] = xiangWanList[i].split('#');
console.log(`\n*****第[${index}]个${$.name}账号*****`);
await login(account, pwd);
if (!$.isLogin) {
continue;
}
await $.wait(sudojia.getRandomWait(1e3, 2e3));
message += `📣====${$.name}账号[${index}]====📣\n`;
await main();
await $.wait(sudojia.getRandomWait(2000, 2500));
}
if (message) {
await notify.sendNotify(`${$.name}`, `${message}`);
}
})().catch((e) => $.logErr(e)).finally(() => $.done());
async function main() {
await sign();
await $.wait(sudojia.getRandomWait(1e3, 2e3));
await getUserInfo();
}
/**
* 登录
*
* @param account
* @param password
* @returns {Promise<void>}
*/
async function login(account, password) {
try {
let cachedToken = await getTokenFromCache("xiangwan", account);
if (cachedToken) {
headers.authorization = `Bearer ${cachedToken}`;
console.log('使用缓存 token 登录,验证中...');
const isValid = await validateToken(cachedToken);
await $.wait(sudojia.getRandomWait(2e3, 3e3));
if (isValid) {
$.isLogin = true;
console.log('token 验证有效✅');
return;
} else {
console.log('缓存 token 验证失效,开始重新登录更新 token...');
}
}
const encryptData = await sudojia.sendRequest(`${baseUrl}/account/account_login`, 'post', headers, {
"params": encryptCredentials(JSON.stringify({
...getCommonParams(),
account: account,
password: password
}))
});
const decryptData = JSON.parse(decryptCredentials(encryptData));
if (200 !== decryptData.status_code) {
$.isLogin = false;
return console.error(`登录失败 ->`, decryptData);
}
console.log('登录成功~');
headers.authorization = `Bearer ${decryptData.data.token}`;
$.isLogin = true;
// 保存 token 到文件
await saveTokenToCache("xiangwan", account, decryptData.data.token);
} catch (e) {
$.isLogin = false;
if (e.response || e.response.data) {
console.error(`登录时发生异常 ->`, e.response.data);
} else {
console.error(`登录时发生异常 ->`, e);
}
}
}
/**
* 签到
*
* @returns {Promise<void>}
*/
async function sign() {
try {
console.log('\n开始执行...');
await $.wait(sudojia.getRandomWait(1e3, 2e3));
const days = moment().format('YYYYMMDD');
const encryptData = await sudojia.sendRequest(`${baseUrl}/discover/sign`, 'post', headers, {
"params": encryptCredentials(JSON.stringify({
...getCommonParams(),
"days": days
}))
});
const decryptData = JSON.parse(decryptCredentials(encryptData));
if (200 !== decryptData.status_code) {
message += `签到失败 -> ${decryptData.message}\n`;
return console.error(`签到失败 ->`, decryptData.message);
}
console.log(`签到成功,恭喜获得:${decryptData.data.score}玩豆`);
message += `签到成功,恭喜获得:${decryptData.data.score}玩豆\n`;
} catch (e) {
console.error(`签到时发生异常 ->`, e);
}
}
/**
* 获取用户信息
*
* @returns {Promise<void>}
*/
async function getUserInfo() {
try {
const encryptData = await sudojia.sendRequest(`${baseUrl}/me/member_info`, 'post', headers, {
"params": encryptCredentials(JSON.stringify({
...getCommonParams()
}))
});
const decryptData = JSON.parse(decryptCredentials(encryptData));
if (200 !== decryptData.status_code) {
return console.error(`获取用户信息时发生异常 ->`, decryptData);
}
const {nickname, mobile, balance} = decryptData.data;
const hiddenMobile = `${mobile.slice(0, 3)}***${mobile.slice(-3)}` || 18888888888;
const displayName = nickname || "吴彦祖";
console.log(`${displayName}(${hiddenMobile})`);
console.log(`当前玩豆:${balance}`);
message += `${nickname}(${hiddenMobile})\n`;
message += `当前玩豆:${balance}\n\n`;
} catch (e) {
console.error(`获取用户信息时发生异常 ->`, e);
}
}
/**
* 验证 token 是否有效
*
* @param token
* @returns {Promise<boolean>}
*/
async function validateToken(token) {
try {
const encryptData = await sudojia.sendRequest(`${baseUrl}/me/member_account`, 'post', {
authorization: `Bearer ${token}`
}, {
"params": encryptCredentials(JSON.stringify({
...getCommonParams()
}))
});
const decryptData = JSON.parse(decryptCredentials(encryptData));
return 200 === decryptData.status_code;
} catch (error) {
console.error('验证 token 时发生异常:', error);
return false;
}
}
/**
* 获取公共请求参数
*
* @returns {Object} 包含公共请求参数的对象
*/
function getCommonParams() {
return {
"app_channel": "xw_100016",
"app_version": "1.3",
"invite_uid": "",
"app_os": "android",
"server_device_id": "176"
};
}
/**
* 加密请求数据
*
* @returns {string} 加密后的Base64字符串
*/
function encryptCredentials(plainText) {
// 创建加密器
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
// 加密数据
let encrypted = cipher.update(plainText, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
/**
* 解密响应数据
*
* @param encryptedText
* @returns {string}
*/
function decryptCredentials(encryptedText) {
// 创建解密器
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
// 解密数据
let decrypted = decipher.update(encryptedText, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
/**
* 从文件中读取 token
*
* @param platform
* @param username
* @returns {Promise<*|null>}
*/
async function getTokenFromCache(platform, username) {
try {
try {
// 检查文件是否存在
await fs.access(TOKEN_CACHE_PATH);
} catch (error) {
console.warn('token 缓存文件不存在,创建一个空文件...');
await fs.writeFile(TOKEN_CACHE_PATH, JSON.stringify({}, null, 2), 'utf8');
return null;
}
const cache = await fs.readFile(TOKEN_CACHE_PATH, 'utf-8');
// 检查文件内容是否为空
if (!cache.trim()) {
console.warn('token 缓存文件内容为空,开始重新登录生成 token 内容');
return null;
}
let cacheObj;
try {
cacheObj = JSON.parse(cache);
} catch (parseError) {
console.error('解析 token 缓存文件失败:', parseError);
return null; // 解析失败时返回 null
}
// 检查平台和用户名是否存在
if (cacheObj[platform] && cacheObj[platform][username]) {
return cacheObj[platform][username];
} else {
console.warn(`token 缓存文件中未找到[${username}]的账号,开始重新登录生成 token`);
return null;
}
} catch (error) {
console.error('读取缓存文件失败:', error);
return null;
}
}
/**
* 将 token 保存到文件
*
* @param platform
* @param username
* @param token
*
* @returns {Promise<void>}
*/
async function saveTokenToCache(platform, username, token) {
try {
let cacheObj = {};
try {
const cache = await fs.readFile(TOKEN_CACHE_PATH, 'utf-8');
if (cache.trim()) {
cacheObj = JSON.parse(cache);
} else {
console.warn('token 缓存文件内容为空,开始初始化为空对象...');
}
} catch (error) {
console.warn('读取缓存文件失败,初始化为空对象:', error);
}
if (!cacheObj[platform]) {
cacheObj[platform] = {};
}
cacheObj[platform][username] = token;
await fs.writeFile(TOKEN_CACHE_PATH, JSON.stringify(cacheObj, null, 2), 'utf-8');
console.log('token 已保存到缓存文件[xiangwan_token_cache.json]');
console.log(`路径:${TOKEN_CACHE_PATH}`);
} catch (error) {
console.error('保存 token 失败:', error);
}
}