#18851 很酷是吧(
首先,我先是查找用户发布的帖子,然后遍历去选择(
先上完整代码
const Client = require('./Nuo_flarum_bot_lib'); // 导入库
const options = {
url: 'https://www.nodeloc.com/', // 论坛地址
auth: {
type: 'cookie', // cookie 登录
cookie: 'flarum_remember=【数据删除】'
}
};
const nodeloc = new Client(options); // 打开一个客户端
async function pay(username, count = 1, comment = "") {
try {
async function _pay(postid, count, comment) {
let req = await nodeloc.fetch(`/api/posts/${postid}/money-rewards`, {
headers: {
"content-type": "application/json; charset=UTF-8",
},
body: JSON.stringify({
data: {
attributes: {
amount: "" + count,
createMoney: false,
comment
}
}
}),
method: "POST",
});
return !!(await req.json())?.data;
}
let req = await nodeloc.fetch(`/api/posts?filter%5Bauthor%5D=${encodeURIComponent(username)}&filter%5Btype%5D=comment&sort=-createdAt&limit=20`);
let userPosts = (await req.json()).data.map(post => post.id);
let pending = true;
let index = 0;
while (pending) {
if (!userPosts[index]) throw new Error();
pending = !await _pay(userPosts[index], count, comment);
index ++;
}
return true;
} catch (error) {
console.error(error);
return false;
}
}
const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const PORT = 6541;
const CONFIG_FILE = path.join(__dirname, 'config.json');
// 读取配置文件
let config = {
totalNL: 1000,
userRequests: {},
ipRequests: {},
};
// 加载配置文件
if (fs.existsSync(CONFIG_FILE)) {
config = JSON.parse(fs.readFileSync(CONFIG_FILE));
}
// 中间件:解析 JSON 请求体
app.use(express.json());
// 主页,提供输入框和按钮
app.get('/', (req, res) => {
res.send(`
<div id="nojavascript" style="position: fixed;top:0;left:0;right:0;bottom:0">Enable JavaScript to next.</div>
<form id="claimForm">
<h1>免费得到 10NL</h1>
<p>剩余 NL: ${config.totalNL}</p>
<input type="text" name="username" placeholder="输入你的 Nodeloc 用户名" required />
<button type="submit">免费得到 10 NL</button>
</form>
<script>
document.getElementById('nojavascript').remove();
document.getElementById('claimForm').addEventListener('submit', function(event) {
event.preventDefault();
const username = this.username.value;
const data = {
username: username
};
const jsonData = JSON.stringify(data);
fetch('/rycell/6541/claim', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: jsonData
})
.then(response => response.text())
.then(data => {
alert(data);
})
.catch((error) => {
alert('Error: ' + error.message);
});
});
</script>
`);
});
// 领取 NL 的路由
app.post('/claim', async (req, res) => {
const username = req.body.username;
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const currentTime = Date.now();
const hourInMillis = 60 * 60 * 1000;
// 检查用户请求限制
if (!config.userRequests[username]) {
config.userRequests[username] = { count: 0, lastClaim: 0 };
}
if (currentTime - config.userRequests[username].lastClaim < hourInMillis) {
if (config.userRequests[username].count >= 1) {
return res.status(429).send('等一下!你太快了,请等待一会后再试!');
}
} else {
config.userRequests[username].count = 0; // Reset count after an hour
}
// 检查 IP 请求限制
if (!config.ipRequests[ip]) {
config.ipRequests[ip] = { count: 0, lastClaim: 0 };
}
if (currentTime - config.ipRequests[ip].lastClaim < hourInMillis) {
if (config.ipRequests[ip].count >= 1) {
return res.status(429).send('等一下!你太快了,请等待一会后再试!');
}
} else {
config.ipRequests[ip].count = 0; // Reset count after an hour
}
// 检查全局限制
if (config.totalNL < 10) {
return res.status(400).send('没有可用的 NL 用于转账');
}
config.userRequests[username].count++;
config.userRequests[username].lastClaim = currentTime;
config.ipRequests[ip].count++;
config.ipRequests[ip].lastClaim = currentTime;
config.totalNL -= 10;
// 执行支付
const success = await pay(username, 10, '');
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
if (success) {
return res.send('成功转账,检查你的 NL~\n你知道吗:你可以在一段时间后再次领取!');
} else {
config.ipRequests[ip].count--;
config.userRequests[username].count--;
config.totalNL += 10;
return res.status(500).send('转账时出现意外错误!');
}
});
// 启动服务器
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
思路:用户点击后,先验证用户是否一段时间内领取过,然后就是直接转账了,转账的思路是这样子的:
- 用api查询20个用户的回帖
- 挨个尝试转账,成功就中止
之前username有个xss,只需要在名称后面加上 &w=任意字符 就可以直接无限领
还有就是疯狂点也可以无限领取(现在修复了, @Yucho 借此多得了点NL
)