【改】Serv00保号,并接入微信推送服务

:heart: 先赞后看,养成习惯 :heart:

偶然间看见佬的woker保号教程,已经很好用了,不过这通知嘛,并不符合中国宝宝体质 :tieba_025:

所以就改了下通知方式,换成了WxPusher / PushPlus,免费好用的推送服务

WxPusher推送

  1. 首先,我们登录后台 WxPusher微信消息推送服务 使用微信注册
  2. 然后,创建应用,接着新建主题,复制主题的TopicId,关注订阅,微信扫码
  3. 最后,去左侧应用管理,获取appToken,保存好,只显示一次

大功告成,就是这么简单 :lark_085:

PushPlus推送

响应佬友需求,添加pushplus推送服务

https://www.pushplus.plus/

微信扫码,实名,获取token,结束 :tieba_025:

Cloudflare

点击左侧 Workers和pages创建创建Worker → 自定义名称,部署 → 进入新建的Worker的设置 → 添加变量和机密(纯文本)-> 触发事件,选择Cron, → 左上角 编辑代码,粘贴下面的worker代码 → 部署

变量

变量名称

ACCOUNTS_JSON

值(类型:文本)

[  
  { "username": "serv00账号", "password": "密码", "panelnum": "与账号保持一致,例如当前s14赛季注册的就填数字14", "type": "serv00" },
  { "username": "ct8账号", "password": "密码", "type": "ct8" }
]

变量名称

PUSH_CHOOSE

值(类型:文本)

wxpusher
pushplus(二选一)

以下变量二选一

变量名称

WXPUSHER_JSON

值(类型:文本)

{
  "appToken": "YOUR_APPTOKEN",
  "topicIds": "YOUR_topicIds"
}

变量名称

PUSHPLUS_JSON

值(类型:文本)

{
  "pushplusToken": "YOUR_TOKEN",
  "channel": "YOUR_CHANNEL"
}
  • channel取值
发送渠道 是否免费 描述
wechat 免费 微信公众号
webhook 免费 第三方webhook;HiFlow连接器、企业微信、钉钉、飞书、server酱、IFTTT;webhook机器人推送
cp 免费 企业微信应用;具体参考企业微信应用推送
mail 免费 邮箱;具体参考邮件渠道使用说明
sms 收费 短信;成功发送1条短信需要10积分(0.1元)

Cron定时任务

建议先设置一分钟测试,正常推送后改成每周或每月一次即可

worker代码

账号登录成功不会单独推送消息,仅推送总结报告(嫌烦 :tieba_006:

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})

addEventListener('scheduled', event => {
    event.waitUntil(handleScheduled(event.scheduledTime))
})

async function handleRequest(request) {
    return new Response('Worker is running')
}

async function handleScheduled(scheduledTime) {
    const accounts = JSON.parse(ACCOUNTS_JSON)
    const results = await loginAccounts(accounts)
    await sendSummary(results)
}

async function loginAccounts(accounts) {
    const results = []
    for (const account of accounts) {
        const result = await loginAccount(account)
        results.push({...account, ...result})
        await delay(Math.floor(Math.random() * 8000) + 1000)
    }
    return results
}

function generateRandomUserAgent() {
    const browsers = ['Chrome', 'Firefox', 'Safari', 'Edge', 'Opera'];
    const browser = browsers[Math.floor(Math.random() * browsers.length)];
    const version = Math.floor(Math.random() * 100) + 1;
    const os = ['Windows NT 10.0', 'Macintosh', 'X11'];
    const selectedOS = os[Math.floor(Math.random() * os.length)];
    const osVersion = selectedOS === 'X11' ? 'Linux x86_64' : selectedOS === 'Macintosh' ? 'Intel Mac OS X 10_15_7' : 'Win64; x64';

    return `Mozilla/5.0 (${selectedOS}; ${osVersion}) AppleWebKit/537.36 (KHTML, like Gecko) ${browser}/${version}.0.0.0 Safari/537.36`;
}

async function loginAccount(account) {
    const {username, password, panelnum, type} = account
    let url = type === 'ct8'
        ? 'https://panel.ct8.pl/login/?next=/'
        : `https://panel${panelnum}.serv00.com/login/?next=/`

    const userAgent = generateRandomUserAgent();

    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'User-Agent': userAgent,
            },
        })

        const pageContent = await response.text()
        const csrfMatch = pageContent.match(/name="csrfmiddlewaretoken" value="([^"]*)"/)
        const csrfToken = csrfMatch ? csrfMatch[1] : null

        if (!csrfToken) {
            throw new Error('CSRF token not found')
        }

        const initialCookies = response.headers.get('set-cookie') || ''

        const formData = new URLSearchParams({
            'username': username,
            'password': password,
            'csrfmiddlewaretoken': csrfToken,
            'next': '/'
        })

        const loginResponse = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Referer': url,
                'User-Agent': userAgent,
                'Cookie': initialCookies,
            },
            body: formData.toString(),
            redirect: 'manual'
        })

        console.log(`Login response status: ${loginResponse.status}`)
        console.log(`Login response headers: ${JSON.stringify(Object.fromEntries(loginResponse.headers))}`)

        const loginResponseBody = await loginResponse.text()
        console.log(`Login response body: ${loginResponseBody.substring(0, 200)}...`)

        if (loginResponse.status === 302 && loginResponse.headers.get('location') === '/') {
            const loginCookies = loginResponse.headers.get('set-cookie') || ''
            const allCookies = combineCookies(initialCookies, loginCookies)

            const dashboardResponse = await fetch(url.replace('/login/', '/'), {
                headers: {
                    'Cookie': allCookies,
                    'User-Agent': userAgent,
                }
            })
            const dashboardContent = await dashboardResponse.text()
            console.log(`Dashboard content: ${dashboardContent.substring(0, 200)}...`)

            if (dashboardContent.includes('href="/logout/"') || dashboardContent.includes('href="/wyloguj/"')) {
                const nowUtc = formatToISO(new Date())
                const nowBeijing = formatToISO(new Date(Date.now() + 8 * 60 * 60 * 1000))
                const message = `<h3>账号 ${username} (${type}) 于北京时间 ${nowBeijing}(UTC时间 ${nowUtc})登录成功!</h3>`
                console.log(message)
                // await sendWxPusherMessage(message)
                return {success: true, message}
            } else {
                const message = `<h3>账号 ${username} (${type}) 登录后未找到登出链接,可能登录失败。</h3>`
                console.error(message)
                await sendWxPusherMessage(message)
                return {success: false, message}
            }
        } else if (loginResponseBody.includes('Nieprawid?owy login lub has?o')) {
            const message = `<h3>(${type}) 账号 ${username} 登录失败:用户名或密码错误。</h3>`
            console.error(message)
            await sendWxPusherMessage(message)
            return {success: false, message}
        } else {
            const message = `<h3>(${type}) 账号 ${username} 登录失败,未知原因。请检查账号和密码是否正确。</h3>`
            console.error(message)
            await sendWxPusherMessage(message)
            return {success: false, message}
        }
    } catch (error) {
        const message = `<h3>(${type}) 账号 ${username} 登录时出现错误: ${error.message}</h3>`
        console.error(message)
        await sendWxPusherMessage(message)
        return {success: false, message}
    }
}

function combineCookies(cookies1, cookies2) {
    const cookieMap = new Map()

    const parseCookies = (cookieString) => {
        cookieString.split(',').forEach(cookie => {
            const [fullCookie] = cookie.trim().split(';')
            const [name, value] = fullCookie.split('=')
            if (name && value) {
                cookieMap.set(name.trim(), value.trim())
            }
        })
    }

    parseCookies(cookies1)
    parseCookies(cookies2)

    return Array.from(cookieMap.entries()).map(([name, value]) => `${name}=${value}`).join('; ')
}

async function sendSummary(results) {
    const successfulLogins = results.filter(r => r.success)
    const failedLogins = results.filter(r => !r.success)

    let summaryMessage = '<h1>登录结果统计</h1>'
    summaryMessage += `<h3>登录成功的账号:${successfulLogins.length}</h3>`
    summaryMessage += `<h3>登录失败的账号:${failedLogins.length}</h3>`

    if (failedLogins.length > 0) {
        summaryMessage += '<h3>登录失败的账号列表</h3>'
        failedLogins.forEach(({username, type, message}) => {
            summaryMessage += `- ${username} (${type}): ${message}\n`
        })
    }

    console.log(summaryMessage)
    await sendWxPusherMessage(summaryMessage)
}

async function sendWxPusherMessage(messageContent) {
    const push = PUSH_CHOOSE;
    try {
        let sendMessageUrl, body;
        if (push === 'wxpusher') {
            const { appToken, topicIds } = JSON.parse(WXPUSHER_JSON);
            sendMessageUrl = 'https://wxpusher.zjiecode.com/api/send/message';
            body = {
                "appToken": appToken,
                "content": messageContent,
                "summary": "Serv00 保号",
                "contentType": 2,
                "topicIds": [topicIds],
                "verifyPay": false,
                "verifyPayType": 0
            };
        } else if (push === 'pushplus') {
            const { pushplusToken, channel } = JSON.parse(PUSHPLUS_JSON);
            sendMessageUrl = 'https://www.pushplus.plus/send';
            body = {
                "token": pushplusToken,
                "title": "Serv00 保号",
                "content": messageContent,
                "template": "html",
                "channel": channel
            };
        } else {
            throw new Error('Unsupported push service');
        }
        const response = await fetch(sendMessageUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(body)
        });

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        console.log('Success:', data);
    } catch (error) {
        console.error('Error sending message:', error);
    }
}


function formatToISO(date) {
    return date.toISOString().replace('T', ' ').replace('Z', '').replace(/\.\d{3}Z/, '')
}

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

参考链接

62 个赞

s7的号登录正常吗?

不到啊,我刚注册的s14是成功了,试试呗

感谢大佬教程

原版的部署了,s7登录异常

那就不行,只改了推送方式

大佬说笑了,你才是佬 :tieba_025:

大佬太强了 :tieba_087:

漂亮,改天抄作业

提醒一下,变量设置按文本来。

3b才是大佬

大佬里边请 :tieba_025:

2 个赞

一开始写了,改排班时候误删了 :tieba_027:

确实不错哈,等我也弄上

择日不如撞日 :lark_085:

免费好用的貌似就这家了,其他的推送服务限制太多

好像还有个推送plus+前不久我还冲了个一块钱做了实名认证

我也有一台serv00,还没想好搭什么,怕搭vpn给我封了,我就这一台。。。

1 个赞

看汇总贴能玩的挺多,搞个alist先

是的,我也觉得pushplus更好用