开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 296|回复: 5
收起左侧

[精币悬赏] 帮我修改下这个绿树田园的脚本

[复制链接]
结帖率:92% (11/12)
发表于 昨天 02:49 | 显示全部楼层 |阅读模式   陕西省西安市
100精币
const crypto = require('crypto')
const https = require('https')
const http = require('http')

// ============ 配置 ============
// 自行更换抓包域名地址
const API_BASE = process.env.TREECOIN_API_BASE || 'https://treecoin.cn/api'
const AUTH_CODES = (process.env.TREECOIN_AUTH_CODE || '').split('&').filter(Boolean)

// AES-256-GCM 加密密钥
const ENCRYPTION_KEY = 'asldhlfhkjsadhfkjsdhfjshjkhfhsadflh'.substring(0, 32)
const ALGORITHM = 'aes-256-gcm'

// ============ 工具函数 ============

/**
* AES-GCM 加密
*/
function aesEncrypt(text) {
    const iv = crypto.randomBytes(12)
    const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY), iv)
    let encrypted = cipher.update(text, 'utf-8')
    encrypted = Buffer.concat([encrypted, cipher.final()])
    return {
        data: encrypted.toString('hex'),
        iv: iv.toString('hex')
    }
}

/**
* 发送 HTTP 请求
*/
function request(path, method, body, token) {
    return new Promise((resolve, reject) => {
        const url = new URL(API_BASE + path)
        const isHttps = url.protocol === 'https:'
        const lib = isHttps ? https : http

        const data = body ? JSON.stringify(body) : null

        const options = {
            hostname: url.hostname,
            port: url.port || (isHttps ? 443 : 80),
            path: url.pathname,
            method: method,
            headers: {
                'Content-Type': 'application/json',
                'User-Agent': 'TreeCoinQinglong/1.0'
            }
        }

        if (data) {
            options.headers['Content-Length'] = Buffer.byteLength(data)
        }

        if (token) {
            options.headers['Authorization'] = `Bearer ${token}`
        }

        const req = lib.request(options, (res) => {
            let chunks = ''
            res.on('data', (chunk) => { chunks += chunk })
            res.on('end', () => {
                try {
                    resolve(JSON.parse(chunks))
                } catch (e) {
                    resolve({ c: 0, msg: '响应解析失败', raw: chunks })
                }
            })
        })

        req.on('error', reject)
        req.setTimeout(15000, () => {
            req.destroy(new Error('请求超时'))
        })

        if (data) req.write(data)
        req.end()
    })
}

/**
* 生成随机设备指纹(16位)
*/
function generateDeviceId() {
    const chars = 'abcdef0123456789'
    let id = ''
    for (let i = 0; i < 16; i++) {
        id += chars.charAt(Math.floor(Math.random() * chars.length))
    }
    return id
}

/**
* 控制台输出带时间戳
*/
function log(msg) {
    const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
    console.log(`[${now}] ${msg}`)
}

/**
* 延迟
*/
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

// ============ 核心逻辑 ============

/**
* 使用授权码登录
*/
async function loginWithAuthCode(authCode) {
    const deviceFingerprint = generateDeviceId()

    const result = await request('/auth/login-by-auth-code', 'POST', {
        authCode,
        device_fingerprint: deviceFingerprint
    })

    if (result.c !== 1 || !result.data) {
        throw new Error(result.msg || '登录失败')
    }

    return {
        token: result.data.token,
        openid: result.data.openid,
        deviceFingerprint: deviceFingerprint,
        userInfo: result.data.user || {}
    }
}

/**
* 执行签到
*/
async function doSignin(token, deviceId) {
    // 加密请求数据 { token, deviceId }
    const payload = JSON.stringify({ token, deviceId })
    const { data, iv } = aesEncrypt(payload)

    const result = await request('/app/signin', 'POST', {
        encryptedData: data,
        iv
    }, token)

    return result
}

/**
* 单账号签到流程
*/
async function signinForAccount(authCode, index) {
    log(`---------- 账号 ${index + 1} ----------`)
    log(`授权码: ${authCode.substring(0, 8)}****`)

    try {
        // 1. 登录
        log('正在登录...')
        const loginResult = await loginWithAuthCode(authCode)
        log(`登录成功!用户: ${loginResult.userInfo.nickName || '未知'} (openid: ${loginResult.openid.substring(0, 8)}...)`)

        const { token, deviceFingerprint } = loginResult

        // 2. 设置页面访问标记
        log('设置签到前置标记...')
        await sleep(500)

        // 3. 签到
        log('执行签到...')
        const signinResult = await doSignin(token, deviceFingerprint)

        if (signinResult.c === 1) {
            const data = signinResult.data || {}
            log('========================================')
            log('           签到成功!')
            log('========================================')
            log(`  连续签到天数: ${data.continuousDays || 1} 天`)
            log(`  当前持有树苗: ${data.vitality || '未知'}`)
            log(`  本次树苗奖励: +${data.baseReward || 0}`)
            if (data.continuousReward && data.continuousReward > 0) {
                log(`  连续签到奖励: +${data.continuousReward} (满7天额外奖励!)`)
            }
            log(`  本次总收益:   +${data.increase || 0} 树苗`)
            log('========================================')
            log('提示: 大树(能量币)收益将在签到后异步发放')
            log('      持有树苗越多,每日大树产币越多!')
            return { success: true, data }
        } else {
            log(`签到结果: ${signinResult.msg || '未知'}`)

            // 今日已签到也算成功
            if (signinResult.msg && signinResult.msg.includes('已签到')) {
                log('今天已经签到过了,明天再来吧!')
                return { success: true, alreadySigned: true }
            }

            return { success: false, msg: signinResult.msg }
        }
    } catch (error) {
        log(`签到失败: ${error.message}`)
        return { success: false, msg: error.message }
    }
}

/**
* 主函数
*/
async function main() {
    console.log('')
    console.log('╔══════════════════════════════════════════╗')
    console.log('║     绿树田园 - 每日签到脚本 (青龙版)     ║')
    console.log('║                                          ║')
    console.log('║  种树赚钱,每日签到,连续7天额外奖励!   ║')
    console.log('║  树苗可兑换真实树苗,为地球添一份绿!    ║')
    console.log('║  当前币价:3.12,自由交易    ║')
    console.log('╚══════════════════════════════════════════╝')
    console.log('')

    if (AUTH_CODES.length === 0) {
        console.log('❌ 未配置授权码!')
        console.log('')
        console.log('请设置环境变量 TREECOIN_AUTH_CODE')
        console.log('获取方式:VX小程序「绿树田园」→ 我的 → 授权码')
        console.log('多账号用 & 分隔')
        console.log('')
        console.log('青龙面板配置:')
        console.log('  环境变量 → 添加 → TREECOIN_AUTH_CODE = 你的授权码')
        console.log('  定时任务 → task treecoin-qinglong-signin.js')
        console.log('  cron表达式: 0 8 * * * (每天8点)')
        return
    }

    log(`共 ${AUTH_CODES.length} 个账号待签到`)
    log(`API地址: ${API_BASE}`)
    console.log('')

    let successCount = 0
    let failCount = 0

    for (let i = 0; i < AUTH_CODES.length; i++) {
        const result = await signinForAccount(AUTH_CODES[i].trim(), i)
        if (result.success) {
            successCount++
        } else {
            failCount++
        }

        // 多账号间隔2秒,避免频率限制
        if (i < AUTH_CODES.length - 1) {
            log('等待2秒后处理下一个账号...')
            await sleep(2000)
        }
    }

    console.log('')
    log('========== 签到汇总 ==========')
    log(`成功: ${successCount} 个账号`)
    log(`失败: ${failCount} 个账号`)
    log('==============================')

    if (failCount > 0) {
        log('部分账号签到失败,请检查授权码是否正确或是否已过期')
    }
}

// 运行
main().catch(err => {
    log(`脚本运行异常: ${err.message}`)
    console.error(err)
})

结帖率:92% (11/12)

签到天数: 4 天

 楼主| 发表于 昨天 02:53 高大上手机用户 | 显示全部楼层   陕西省西安市
网址https://treecoin.cn/
回复

使用道具 举报

结帖率:93% (26/28)

签到天数: 10 天

发表于 昨天 03:25 | 显示全部楼层   山东省临沂市
jyfinn 发表于 2026-7-10 02:53
网址https://treecoin.cn/

没有授权码
回复

使用道具 举报

结帖率:93% (26/28)

签到天数: 10 天

发表于 昨天 03:26 | 显示全部楼层   山东省临沂市
什么脚本?js吗?
回复

使用道具 举报

结帖率:92% (11/12)

签到天数: 4 天

 楼主| 发表于 昨天 03:30 高大上手机用户 | 显示全部楼层   陕西省咸阳市
是永乐哟 发表于 2026-7-10 03:26
什么脚本?js吗?

对,授权码关注公众号就有
回复

使用道具 举报

结帖率:92% (11/12)

签到天数: 4 天

 楼主| 发表于 昨天 05:01 高大上手机用户 | 显示全部楼层   陕西省咸阳市
const crypto = require('crypto')
const https = require('https')
const http = require('http')
const zlib = require('zlib')

// ============ 配置 ============
// 接口地址,可通过环境变量覆盖
const API_BASE = process.env.TREECOIN_API_BASE || 'https://treecoin.cn/api'
const AUTH_CODES = (process.env.TREECOIN_AUTH_CODE || '').split('&').filter(Boolean)
// 可选:固定设备指纹(抓包获取可降低风控,通过环境变量 TREECOIN_DEVICE_FP 配置)
const FIXED_DEVICE_FP = process.env.TREECOIN_DEVICE_FP || 'BROWSER_1783593257377_qrbf23j6i'

// 加密算法
const ALGORITHM = 'aes-256-cbc'

// ============ 工具函数 ============

/**
* AES-CBC 加密
*/
function aesEncrypt(text, sessionKeyBase64, nonceUuid) {
    const key = Buffer.from(sessionKeyBase64, 'base64')
    const iv = Buffer.from(nonceUuid.replace(/-/g, ''), 'hex')
    const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
    let encrypted = cipher.update(text, 'utf8', 'base64')
    encrypted += cipher.final('base64')
    return encrypted
}

/**
* AES-CBC 解密
*/
function aesDecrypt(cipherBase64, sessionKeyBase64, nonceUuid) {
    const key = Buffer.from(sessionKeyBase64, 'base64')
    const iv = Buffer.from(nonceUuid.replace(/-/g, ''), 'hex')
    const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
    let decrypted = decipher.update(cipherBase64, 'base64', 'utf8')
    decrypted += decipher.final('utf8')
    return JSON.parse(decrypted)
}

/**
* 发送 HTTP 请求
*/
function request(path, method, body, deviceFp) {
    return new Promise((resolve, reject) => {
        const url = new URL(API_BASE + path)
        const isHttps = url.protocol === 'https:'
        const lib = isHttps ? https : http

        const data = body ? JSON.stringify(body) : null

        const options = {
            hostname: url.hostname,
            port: url.port || (isHttps ? 443 : 80),
            path: url.pathname,
            method: method,
            headers: {
                'Content-Type': 'application/json',
                'Accept': '*/*',
                'Accept-Encoding': 'gzip, deflate',
                'Origin': 'https://treecoin.cn',
                'Referer': 'https://treecoin.cn/home',
                'User-Agent': 'Mozilla/5.0 (Linux; Android 14; 24069RA21C Build/UKQ1.240116.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/146.0.7680.178 Mobile Safari/537.36 XWEB/1460217 MMWEBSDK/20260202 MicroMessenger/8.0.71.3080 WeChat/arm64 NetType/4G Language/zh_CN',
                'X-Requested-With': 'com.tencent.mm'
            }
        }

        if (data) {
            options.headers['Content-Length'] = Buffer.byteLength(data)
        }

        if (deviceFp) {
            options.headers['X-Device-Fingerprint'] = deviceFp
        }

        const req = lib.request(options, (res) => {
            // 自动处理压缩响应
            let stream = res
            const encoding = res.headers['content-encoding']
            if (encoding === 'gzip') stream = res.pipe(zlib.createGunzip())
            else if (encoding === 'deflate') stream = res.pipe(zlib.createInflate())

            let chunks = ''
            stream.on('data', (chunk) => { chunks += chunk })
            stream.on('end', () => {
                try {
                    resolve(JSON.parse(chunks))
                } catch (e) {
                    resolve({ c: 0, msg: '响应解析失败', raw: chunks })
                }
            })
        })

        req.on('error', reject)
        req.setTimeout(15000, () => {
            req.destroy(new Error('请求超时'))
        })

        if (data) req.write(data)
        req.end()
    })
}

/**
* 生成符合平台规则的设备指纹
*/
function generateDeviceId() {
    const ts = Date.now()
    const random = Math.random().toString(36).substring(2, 12)
    return `BROWSER_${ts}_${random}`
}

/**
* 控制台输出带时间戳
*/
function log(msg) {
    const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
    console.log(`[${now}] ${msg}`)
}

/**
* 延迟
*/
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

// ============ 核心逻辑 ============

/**
* 使用授权码登录
*/
async function loginWithAuthCode(authCode) {
    const deviceFingerprint = FIXED_DEVICE_FP || generateDeviceId()

    const result = await request('/auth/login-by-auth-code', 'POST', {
        authCode,
        device_fingerprint: deviceFingerprint
    }, deviceFingerprint)

    if (result.c !== 1 || !result.data) {
        throw new Error(result.msg || '登录失败')
    }

    const userInfo = (result.data.user && result.data.user.dataValues) || result.data.user || {}
    const session = result.data.session || {}

    return {
        token: result.data.token,
        sessionId: session.sessionId,
        sessionKey: session.sessionKey,
        openid: result.data.openid,
        deviceFingerprint: deviceFingerprint,
        userInfo: userInfo
    }
}

/**
* 前置会话校验(签到必走步骤)
*/
async function preCheck(sessionId, sessionKey, deviceFp) {
    const nonce = crypto.randomUUID()
    const timestamp = Date.now()
    const payload = JSON.stringify({ timestamp })
    const encryptedData = aesEncrypt(payload, sessionKey, nonce)

    return request('/app/t', 'POST', {
        sessionId,
        encryptedData,
        nonce,
        timestamp
    }, deviceFp)
}

/**
* 执行签到
*/
async function doSignin(sessionId, sessionKey, deviceId, token) {
    const nonce = crypto.randomUUID()
    const timestamp = Date.now()
    // 加密请求数据
    const payload = JSON.stringify({ timestamp, token })
    const encryptedData = aesEncrypt(payload, sessionKey, nonce)

    const result = await request('/app/signin', 'POST', {
        sessionId,
        encryptedData,
        nonce,
        timestamp
    }, deviceId)

    // 解密加密响应
    if (result.encrypted && result.data) {
        return aesDecrypt(result.data, sessionKey, nonce)
    }
    return result
}

/**
* 单账号签到流程
*/
async function signinForAccount(authCode, index) {
    log(`---------- 账号 ${index + 1} ----------`)
    log(`授权码: ${authCode.substring(0, 8)}****`)

    try {
        // 1. 登录
        log('正在登录...')
        const loginResult = await loginWithAuthCode(authCode)
        log(`登录成功!用户: ${loginResult.userInfo.nickName || '未知'} (openid: ${loginResult.openid.substring(0, 8)}...)`)

        const { token, sessionId, sessionKey, deviceFingerprint } = loginResult

        // 2. 设置签到前置标记
        log('设置签到前置标记...')
        await preCheck(sessionId, sessionKey, deviceFingerprint)
        await sleep(350)

        // 3. 签到
        log('执行签到...')
        const signinResult = await doSignin(sessionId, sessionKey, deviceFingerprint, token)

        if (signinResult.c === 1) {
            const data = signinResult.data || {}
            log('========================================')
            log('           签到成功!')
            log('========================================')
            log(`  连续签到天数: ${data.continuousDays || 1} 天`)
            log(`  当前持有树苗: ${data.vitality || '未知'}`)
            log(`  本次树苗奖励: +${data.baseReward || 0}`)
            if (data.continuousReward && data.continuousReward > 0) {
                log(`  连续签到奖励: +${data.continuousReward} (满7天额外奖励!)`)
            }
            log(`  本次总收益:   +${data.increase || 0} 树苗`)
            log('========================================')
            log('提示: 大树(能量币)收益将在签到后异步发放')
            log('      持有树苗越多,每日大树产币越多!')
            return { success: true, data }
        } else {
            log(`签到结果: ${signinResult.msg || '未知'}`)

            // 今日已签到也算成功
            if (signinResult.msg && signinResult.msg.includes('已签到')) {
                log('今天已经签到过了,明天再来吧!')
                return { success: true, alreadySigned: true }
            }

            return { success: false, msg: signinResult.msg }
        }
    } catch (error) {
        log(`签到失败: ${error.message}`)
        return { success: false, msg: error.message }
    }
}

/**
* 主函数
*/
async function main() {
    console.log('')
    console.log('╔══════════════════════════════════════════╗')
    console.log('║     绿树田园 - 每日签到脚本 (青龙版)     ║')
    console.log('║                                          ║')
    console.log('║  种树赚钱,每日签到,连续7天额外奖励!   ║')
    console.log('║  树苗可兑换真实树苗,为地球添一份绿!    ║')
    console.log('║  当前币价:3.12,自由交易    ║')
    console.log('╚══════════════════════════════════════════╝')
    console.log('')

    if (AUTH_CODES.length === 0) {
        console.log('❌ 未配置授权码!')
        console.log('')
        console.log('请设置环境变量 TREECOIN_AUTH_CODE')
        console.log('获取方式:VX小程序「绿树田园」→ 我的 → 授权码')
        console.log('多账号用 & 分隔')
        console.log('')
        console.log('青龙面板配置:')
        console.log('  环境变量 → 添加 → TREECOIN_AUTH_CODE = 你的授权码')
        console.log('  定时任务 → task treecoin-qinglong-signin.js')
        console.log('  cron表达式: 0 8 * * * (每天8点)')
        return
    }

    log(`共 ${AUTH_CODES.length} 个账号待签到`)
    log(`API地址: ${API_BASE}`)
    console.log('')

    let successCount = 0
    let failCount = 0

    for (let i = 0; i < AUTH_CODES.length; i++) {
        const result = await signinForAccount(AUTH_CODES[i].trim(), i)
        if (result.success) {
            successCount++
        } else {
            failCount++
        }

        // 多账号间隔10秒,降低风控风险
        if (i < AUTH_CODES.length - 1) {
            log('等待10秒后处理下一个账号...')
            await sleep(10000)
        }
    }

    console.log('')
    log('========== 签到汇总 ==========')
    log(`成功: ${successCount} 个账号`)
    log(`失败: ${failCount} 个账号`)
    log('==============================')

    if (failCount > 0) {
        log('部分账号签到失败,请检查授权码是否正确或是否已过期')
    }
}

// 运行
main().catch(err => {
    log(`脚本运行异常: ${err.message}`)
    console.error(err)
})
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表