mirror of
https://github.com/Jerryplusy/crystelf-plugin.git
synced 2025-10-13 21:29:19 +00:00
feat:增加手性碳验证方法
This commit is contained in:
parent
7b1fe3e402
commit
ec0ad4101f
95
apps/auth-set.js
Normal file
95
apps/auth-set.js
Normal file
@ -0,0 +1,95 @@
|
||||
import configControl from '../lib/config/configControl.js';
|
||||
|
||||
export class carbonAuthSetting extends plugin {
|
||||
constructor() {
|
||||
super({
|
||||
name: 'carbonAuth-setting',
|
||||
dsc: '手性碳验证设置',
|
||||
event: 'message.group',
|
||||
priority: -1000,
|
||||
rule: [
|
||||
{ reg: '^#开启验证$', fnc: 'enableAuth' },
|
||||
{ reg: '^#关闭验证$', fnc: 'disableAuth' },
|
||||
{ reg: '^#切换验证模式$', fnc: 'switchMode' },
|
||||
{ reg: '^#设置验证(提示|困难)模式(开启|关闭)$', fnc: 'setCarbonMode' },
|
||||
{ reg: '^#设置验证次数(\\d+)$', fnc: 'setFrequency' },
|
||||
{ reg: '^#设置撤回(开启|关闭)$', fnc: 'setRecall' },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
//获取奇妙的配置
|
||||
async _getCfg(e) {
|
||||
const cfg = (await configControl.get('auth')) || {};
|
||||
const groupCfg = cfg.groups[e.group_id] || JSON.parse(JSON.stringify(cfg.default));
|
||||
return { cfg, groupCfg };
|
||||
}
|
||||
|
||||
//保存奇妙的配置
|
||||
async _saveCfg(e, cfg, groupCfg) {
|
||||
cfg.groups[e.group_id] = groupCfg;
|
||||
await configControl.set('auth', cfg);
|
||||
}
|
||||
|
||||
//在制定群开启验证
|
||||
async enableAuth(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
groupCfg.enable = true;
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply('本群已开启入群验证,验证模式为数字验证..', true);
|
||||
}
|
||||
|
||||
async disableAuth(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
groupCfg.enable = false;
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply('已关闭本群新人验证..', true);
|
||||
}
|
||||
|
||||
async switchMode(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
groupCfg.carbon.enable = !groupCfg.carbon.enable;
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply(
|
||||
groupCfg.carbon.enable ? '已切换为手性碳验证模式..' : '已切换为数字验证模式..',
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
async setCarbonMode(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const [, type, state] = e.msg.match(/^#设置验证(提示|困难)模式(开启|关闭)$/);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
if (type === '提示') groupCfg.carbon.hint = state === '开启';
|
||||
if (type === '困难') groupCfg.carbon['hard-mode'] = state === '开启';
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply(`已${state}手性碳${type}模式..`, true);
|
||||
}
|
||||
|
||||
async setFrequency(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const [, num] = e.msg.match(/^#设置验证次数(\d+)$/);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
groupCfg.frequency = parseInt(num);
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply(`已将最大尝试次数设置为 ${num}..`, true);
|
||||
}
|
||||
|
||||
async setRecall(e) {
|
||||
if (!(e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))
|
||||
return e.reply('只有群主或管理员可以设置验证..', true);
|
||||
const [, state] = e.msg.match(/^#设置撤回(开启|关闭)$/);
|
||||
const { cfg, groupCfg } = await this._getCfg(e);
|
||||
groupCfg.recall = state === '开启';
|
||||
await this._saveCfg(e, cfg, groupCfg);
|
||||
return e.reply(`已${state}错误回答自动撤回功能..`, true);
|
||||
}
|
||||
}
|
215
apps/auth.js
Normal file
215
apps/auth.js
Normal file
@ -0,0 +1,215 @@
|
||||
import configControl from '../lib/config/configControl.js';
|
||||
import axios from 'axios';
|
||||
import tools from '../components/tool.js';
|
||||
import Group from '../lib/yunzai/group.js';
|
||||
import Message from '../lib/yunzai/message.js';
|
||||
|
||||
export class CarbonAuth extends plugin {
|
||||
constructor() {
|
||||
super({
|
||||
name: 'carbon-auth',
|
||||
dsc: '手性碳验证',
|
||||
event: 'message.group',
|
||||
priority: -114514,
|
||||
rule: [
|
||||
{ reg: '^#绕过验证([\\s\\S]*)?$', fnc: 'cmdBypass' },
|
||||
{ reg: '^#重新验证([\\s\\S]*)?$', fnc: 'cmdRevalidate' },
|
||||
],
|
||||
});
|
||||
this.pending = new Map();
|
||||
|
||||
//答案监听
|
||||
Bot.on?.('message.group', async (e) => {
|
||||
const key = `${e.group_id}_${e.user_id}`;
|
||||
//logger.info(key);
|
||||
const session = this.pending.get(key);
|
||||
if (!session) return;
|
||||
session.tries++;
|
||||
const { type, answer, tries, cfg } = session;
|
||||
|
||||
const pass = async () => {
|
||||
this.pending.delete(key);
|
||||
const redisKey = `Yz:pendingWelcome:${e.group_id}:${e.user_id}`;
|
||||
const cached = await redis.get(redisKey);
|
||||
if (cached) {
|
||||
try {
|
||||
const msgList = JSON.parse(cached);
|
||||
await e.reply(msgList);
|
||||
} finally {
|
||||
await redis.del(redisKey);
|
||||
}
|
||||
} else {
|
||||
return await e.reply('验证通过,欢迎加入本群~', true);
|
||||
}
|
||||
};
|
||||
|
||||
if (type === 'math') {
|
||||
const msgStr = (e.message || [])
|
||||
.filter((m) => m.type === 'text')
|
||||
.map((m) => m.text)
|
||||
.join('')
|
||||
.trim();
|
||||
const num = parseInt(msgStr, 10);
|
||||
if (!isNaN(num) && num === answer) return pass();
|
||||
if (tries >= cfg.frequency) {
|
||||
this.pending.delete(key);
|
||||
if (cfg.recall) await Message.deleteMsg(e, e.message_id);
|
||||
e.reply([segment.at(e.user_id), '验证失败,你错太多次辣!'], true);
|
||||
return await Group.groupKick(e, e.user_id, e.group_id, false);
|
||||
}
|
||||
if (cfg.recall) await Message.deleteMsg(e, e.message_id);
|
||||
return e.reply(
|
||||
[segment.at(e.user_id), `回答错了呢,你还有${cfg.frequency - tries}次机会,再试试看?`],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if (type === 'carbon') {
|
||||
const msgStr = (e.message || [])
|
||||
.filter((m) => m.type === 'text')
|
||||
.map((m) => m.text)
|
||||
.join('');
|
||||
const msgRegions = msgStr
|
||||
.toUpperCase()
|
||||
.replace(/,/g, ',')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const rightRegions = answer.map((r) => r.toUpperCase());
|
||||
|
||||
let correct;
|
||||
if (cfg.carbon['hard-mode']) {
|
||||
correct = rightRegions.every((r) => msgRegions.includes(r));
|
||||
} else {
|
||||
correct = rightRegions.some((r) => msgRegions.includes(r));
|
||||
}
|
||||
|
||||
if (correct) return pass();
|
||||
if (tries >= cfg.frequency) {
|
||||
if (cfg.recall) await Message.deleteMsg(e, e.message_id);
|
||||
this.pending.delete(key);
|
||||
e.reply([segment.at(e.user_id), '验证失败,你错太多次辣!'], true);
|
||||
return await Group.groupKick(e, e.user_id, e.group_id, false);
|
||||
}
|
||||
if (cfg.recall) await Message.deleteMsg(e, e.message_id);
|
||||
return e.reply(
|
||||
[segment.at(e.user_id), `回答错了呢,你还有${cfg.frequency - tries}次机会,再试试看?`],
|
||||
true
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
//主动退群
|
||||
Bot.on?.('notice.group.decrease', async (e) => {
|
||||
const key = `${e.group_id}_${e.user_id}`;
|
||||
if (this.pending.has(key)) {
|
||||
this.pending.delete(key);
|
||||
logger.mark(`[crystelf-plugin] 用户 ${e.user_id} 主动退群,验证流程结束..`);
|
||||
e.reply('害,怎么跑路了');
|
||||
}
|
||||
});
|
||||
|
||||
//加群事件
|
||||
Bot.on?.('notice.group.increase', async (e) => {
|
||||
if (e.isMaster) return true;
|
||||
await this.auth(e, e.group_id, e.user_id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证
|
||||
* @param e 事件
|
||||
* @param group_id 群号
|
||||
* @param user_id 带验证用户id
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
async auth(e, group_id, user_id) {
|
||||
const cfg = await configControl.get('auth');
|
||||
if (!cfg) return;
|
||||
const groupCfg = cfg.groups[group_id] || cfg.default;
|
||||
if (!groupCfg.enable) return;
|
||||
const key = `${group_id}_${user_id}`;
|
||||
|
||||
if (groupCfg.carbon.enable) {
|
||||
try {
|
||||
const res = await axios.post(`${cfg.url}/captcha/chiralCarbon/getChiralCarbonCaptcha`, {
|
||||
answer: true,
|
||||
hint: groupCfg.carbon.hint,
|
||||
});
|
||||
if (!res.data?.data?.data) return e.reply('获取验证图失败,请稍后重试..');
|
||||
const { base64, regions } = res.data.data.data;
|
||||
const regionCount = regions.length;
|
||||
this.pending.set(key, { type: 'carbon', answer: regions, tries: 0, cfg: groupCfg });
|
||||
e.reply([
|
||||
segment.at(user_id),
|
||||
segment.image(base64),
|
||||
`上图中有一块或多块区域含有手性碳原子\n为了加入本群,你需要在${groupCfg.timeout}秒内正确找出${groupCfg.carbon['hard-mode'] ? '全部含有手性碳的区域' : '其中任意一块包含手性碳的区域'}\n回答的话,直接回复区域代号即可,多个区域用逗号隔开\n提示一下,本图共有${regionCount}块手性碳区域噢..`,
|
||||
]);
|
||||
} catch (err) {
|
||||
logger.error('[crystelf-plugin] 请求手性碳验证API失败..', err);
|
||||
}
|
||||
} else {
|
||||
await tools.sleep(500);
|
||||
const a = Math.floor(Math.random() * 100);
|
||||
const b = Math.floor(Math.random() * 100);
|
||||
const op = Math.random() > 0.5 ? '+' : '-';
|
||||
const ans = op === '+' ? a + b : a - b;
|
||||
this.pending.set(key, { type: 'math', answer: ans, tries: 0, cfg: groupCfg });
|
||||
e.reply([segment.at(user_id), `请在${groupCfg.timeout}秒内发送${a} ${op} ${b}的计算结果..`]);
|
||||
}
|
||||
|
||||
if (groupCfg.timeout > 60) {
|
||||
setTimeout(
|
||||
async () => {
|
||||
if (this.pending.has(key)) {
|
||||
await e.reply([segment.at(user_id), `小朋友,你还有1分钟的时间完成验证噢~`]);
|
||||
}
|
||||
},
|
||||
(groupCfg.timeout - 60) * 1000
|
||||
);
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
if (this.pending.has(key)) {
|
||||
this.pending.delete(key);
|
||||
await e.reply([segment.at(user_id), `小朋友,验证超时啦!请重新申请入群~`]);
|
||||
await Group.groupKick(e, e.user_id, e.group_id, false);
|
||||
}
|
||||
}, groupCfg.timeout * 1000);
|
||||
}
|
||||
|
||||
async cmdBypass(e) {
|
||||
if (!(e.sender && (e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))) {
|
||||
return e.reply('只有群主或管理员可以使用此命令..', true);
|
||||
}
|
||||
const atElem = (e.message || []).find((m) => m.type === 'at');
|
||||
if (!atElem || !atElem.qq) return e.reply('你想绕过谁?', true);
|
||||
const targetId = Number(atElem.qq);
|
||||
const groupId = e.group_id;
|
||||
const key = `${groupId}_${targetId}`;
|
||||
if (this.pending.has(key)) this.pending.delete(key);
|
||||
const redisKey = `Yz:pendingWelcome:${groupId}:${targetId}`;
|
||||
const cached = await redis.get(redisKey);
|
||||
if (cached) {
|
||||
try {
|
||||
const msgList = JSON.parse(cached);
|
||||
await e.reply(msgList);
|
||||
} finally {
|
||||
await redis.del(redisKey);
|
||||
}
|
||||
} else {
|
||||
return await e.reply([segment.at(targetId), '欢迎加入本群~'], true);
|
||||
}
|
||||
}
|
||||
|
||||
async cmdRevalidate(e) {
|
||||
if (!(e.sender && (e.sender.role === 'owner' || e.sender.role === 'admin' || e.isMaster))) {
|
||||
return e.reply('只有群主或管理员可以使用此命令..', true);
|
||||
}
|
||||
let atElem = (e.message || []).find((m) => m.type === 'at');
|
||||
if (!atElem || !atElem.qq) return e.reply('你要验证谁?', true);
|
||||
const targetId = Number(atElem.qq);
|
||||
await this.auth(e, e.group_id, targetId);
|
||||
}
|
||||
}
|
16
apps/poke.js
16
apps/poke.js
@ -3,6 +3,7 @@ import tool from '../components/tool.js';
|
||||
import axios from 'axios';
|
||||
import configControl from '../lib/config/configControl.js';
|
||||
import ConfigControl from '../lib/config/configControl.js';
|
||||
import Group from '../lib/yunzai/group.js';
|
||||
|
||||
export default class ChuochuoPlugin extends plugin {
|
||||
constructor() {
|
||||
@ -51,13 +52,7 @@ async function pokeMaster(e) {
|
||||
|
||||
async function masterPoke(e) {
|
||||
logger.info(`跟主人一起戳!`);
|
||||
if (e.target_id !== e.uin) {
|
||||
await e.bot.sendApi('group_poke', {
|
||||
group_id: e.group_id,
|
||||
user_id: e.target_id,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
if (e.target_id !== e.uin) await Group.groupPoke(e, e.target_id, e.group_id);
|
||||
}
|
||||
|
||||
async function handleBotPoke(e) {
|
||||
@ -75,10 +70,11 @@ async function handleBotPoke(e) {
|
||||
await e.reply(res.data.data, false, 110);
|
||||
if (Math.random() < replyPoke) {
|
||||
await tool.sleep(1000);
|
||||
await e.bot.sendApi('group_poke', { group_id: e.group_id, user_id: e.operator_id });
|
||||
return await Group.groupPoke(e, e.operator_id, e.group_id);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
await e.reply(
|
||||
return await e.reply(
|
||||
`戳一戳出错了!${configControl.get('profile')?.nickName}不知道该说啥好了..`,
|
||||
false,
|
||||
{ recallMsg: 60 }
|
||||
@ -86,7 +82,7 @@ async function handleBotPoke(e) {
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('戳一戳请求失败', err);
|
||||
await e.reply(
|
||||
return await e.reply(
|
||||
`戳一戳出错了!${configControl.get('profile')?.nickName}不知道该说啥好了..`,
|
||||
false,
|
||||
{ recallMsg: 60 }
|
||||
|
@ -1,4 +1,5 @@
|
||||
import configControl from '../lib/config/configControl.js';
|
||||
import tools from '../components/tool.js';
|
||||
|
||||
export class welcomeNewcomer extends plugin {
|
||||
constructor() {
|
||||
@ -10,25 +11,31 @@ export class welcomeNewcomer extends plugin {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新人入群欢迎
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async accept(e) {
|
||||
try {
|
||||
await tools.sleep(600);
|
||||
if (e.user_id === e.self_id) return;
|
||||
const groupId = e.group_id;
|
||||
const cdKey = `Yz:newcomers:${groupId}`;
|
||||
if (await redis.get(cdKey)) return;
|
||||
await redis.set(cdKey, '1', { EX: 30 });
|
||||
const allCfg = configControl.get('newcomer') || {};
|
||||
const cfg = allCfg[groupId] || {};
|
||||
const newcomerCfg = (await configControl.get('newcomer')) || {};
|
||||
const welcomeCfg = newcomerCfg[groupId] || {};
|
||||
const authCfg = await configControl.get('auth');
|
||||
const groupAuthCfg = authCfg?.groups?.[groupId] || authCfg?.default || {};
|
||||
const msgList = [segment.at(e.user_id)];
|
||||
if (cfg.text) msgList.push(cfg.text);
|
||||
if (cfg.image) msgList.push(segment.image(cfg.image));
|
||||
if (!cfg.text && !cfg.image) msgList.push('欢迎新人~!');
|
||||
if (welcomeCfg.text) msgList.push(welcomeCfg.text);
|
||||
if (welcomeCfg.image) msgList.push(segment.image(welcomeCfg.image));
|
||||
if (!welcomeCfg.text && !welcomeCfg.image) msgList.push('欢迎新人~!');
|
||||
if (groupAuthCfg?.enable) {
|
||||
// 缓存欢迎消息
|
||||
const redisKey = `Yz:pendingWelcome:${groupId}:${e.user_id}`;
|
||||
await redis.set(redisKey, JSON.stringify(msgList), { EX: 300 });
|
||||
return;
|
||||
}
|
||||
// 未开启验证
|
||||
await e.reply(msgList);
|
||||
} catch (e) {
|
||||
} catch (err) {
|
||||
return e.reply('加群欢迎出现错误,请重新设置加群欢迎', true);
|
||||
}
|
||||
}
|
||||
|
16
config/auth.json
Normal file
16
config/auth.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"url": "https://carbon.crystelf.top",
|
||||
"default": {
|
||||
"enable": false,
|
||||
"carbon": {
|
||||
"enable": false,
|
||||
"hint": true,
|
||||
"hard-mode": false
|
||||
},
|
||||
"timeout": 180,
|
||||
"recall": true,
|
||||
"frequency": 5
|
||||
},
|
||||
"groups": {
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
"debug": true,
|
||||
"core": true,
|
||||
"maxFeed": 10,
|
||||
"adapter": "lgr",
|
||||
"poke": true,
|
||||
"60s": true,
|
||||
"fanqie": true,
|
||||
|
@ -1,16 +1,32 @@
|
||||
import ConfigControl from '../config/configControl.js';
|
||||
const Group = {
|
||||
/**
|
||||
* 群戳一戳
|
||||
* @param e
|
||||
* @param user_id 被戳的用户
|
||||
* @param group_id 群号
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
async groupPoke(e, user_id, group_id) {
|
||||
return await e.bot.sendApi('group_poke', {
|
||||
group_id: group_id,
|
||||
user_id: user_id,
|
||||
});
|
||||
},
|
||||
|
||||
class NapcatGroup {}
|
||||
class LgrGroup {}
|
||||
|
||||
async function getGroupAdapter() {
|
||||
const adapter = (await ConfigControl.get('config'))?.adapter;
|
||||
if (!adapter || adapter === 'nc' || adapter === 'napcat') {
|
||||
return new NapcatGroup();
|
||||
} else if (adapter === 'lgr' || adapter === 'lagrange') {
|
||||
return new LgrGroup();
|
||||
}
|
||||
return new NapcatGroup();
|
||||
}
|
||||
|
||||
export default await getGroupAdapter();
|
||||
/**
|
||||
* 群踢人
|
||||
* @param e
|
||||
* @param user_id 要踢的人
|
||||
* @param group_id 群号
|
||||
* @param ban 是否允许再次加群
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
async groupKick(e, user_id, group_id, ban) {
|
||||
return await e.bot.sendApi('set_group_kick', {
|
||||
user_id: user_id,
|
||||
group_id: group_id,
|
||||
reject_add_request: ban,
|
||||
});
|
||||
},
|
||||
};
|
||||
export default Group;
|
||||
|
@ -1,16 +1,14 @@
|
||||
import ConfigControl from '../config/configControl.js';
|
||||
|
||||
class NapcatMessage {}
|
||||
class LgrMessage {}
|
||||
|
||||
async function getMessageAdapter() {
|
||||
const adapter = (await ConfigControl.get('config'))?.adapter;
|
||||
if (!adapter || adapter === 'nc' || adapter === 'napcat') {
|
||||
return new NapcatMessage();
|
||||
} else if (adapter === 'lgr' || adapter === 'lagrange') {
|
||||
return new LgrMessage();
|
||||
}
|
||||
return new NapcatMessage();
|
||||
}
|
||||
|
||||
export default await getMessageAdapter();
|
||||
const Message = {
|
||||
/**
|
||||
* 群撤回消息
|
||||
* @param e
|
||||
* @param message_id 消息id
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
async deleteMsg(e, message_id) {
|
||||
return await e.bot.sendApi('delete_msg', {
|
||||
message_id: message_id,
|
||||
});
|
||||
},
|
||||
};
|
||||
export default Message;
|
||||
|
@ -1,16 +1,3 @@
|
||||
import ConfigControl from '../config/configControl.js';
|
||||
const Self = {};
|
||||
|
||||
class NapcatSelf {}
|
||||
class LgrSelf {}
|
||||
|
||||
async function getSelfAdapter() {
|
||||
const adapter = (await ConfigControl.get('config'))?.adapter;
|
||||
if (!adapter || adapter === 'nc' || adapter === 'napcat') {
|
||||
return new NapcatSelf();
|
||||
} else if (adapter === 'lgr' || adapter === 'lagrange') {
|
||||
return new LgrSelf();
|
||||
}
|
||||
return new NapcatSelf();
|
||||
}
|
||||
|
||||
export default await getSelfAdapter();
|
||||
export default Self;
|
||||
|
Loading…
x
Reference in New Issue
Block a user