mirror of
https://github.com/crystelf/crystelf-admin.git
synced 2025-12-05 13:41:57 +00:00
feat:111
This commit is contained in:
parent
9cda3fe7f0
commit
fac2d00027
@ -13,6 +13,11 @@ export default class CoreRestart extends plugin {
|
|||||||
fnc: 'restart',
|
fnc: 'restart',
|
||||||
permission: 'master',
|
permission: 'master',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: '^test$',
|
||||||
|
fnc: 'test',
|
||||||
|
permission: 'master',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -35,4 +40,14 @@ export default class CoreRestart extends plugin {
|
|||||||
await e.reply(`核心重启花的时间有点久了呢..${restartTime?.data?.data}`, true);
|
await e.reply(`核心重启花的时间有点久了呢..${restartTime?.data?.data}`, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async test(e) {
|
||||||
|
logger.info(configControl.get());
|
||||||
|
|
||||||
|
await configControl.set('napcat', {
|
||||||
|
basePath: '114514',
|
||||||
|
userPath: '44444',
|
||||||
|
});
|
||||||
|
logger.info(configControl.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
202
apps/login.js
202
apps/login.js
@ -1,11 +1,209 @@
|
|||||||
|
import plugin from '../../../lib/plugins/plugin.js';
|
||||||
|
import path from 'path';
|
||||||
|
import ConfigControl from '../lib/config/configControl.js';
|
||||||
|
import config from '../../../lib/config/config.js';
|
||||||
|
import configControl from '../lib/config/configControl.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
import Meme from '../lib/core/meme.js';
|
||||||
|
|
||||||
|
const configPath = path.join(process.cwd(), 'data/crystelf/config');
|
||||||
|
const loginSessions = new Map(); //正在进行的登录会话
|
||||||
|
|
||||||
export default class LoginService extends plugin {
|
export default class LoginService extends plugin {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
name: 'Onebot登录相关服务',
|
name: 'Onebot登录相关服务',
|
||||||
dsc: '方便操作',
|
dsc: '方便操作',
|
||||||
rule: [],
|
event: 'message',
|
||||||
|
priority: 50,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#登录(\\d+)?$',
|
||||||
|
fnc: 'loginHandler',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#绑定账号\\s+\\d+$',
|
||||||
|
fnc: 'bindAccount',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#解绑账号\\s+\\d+$',
|
||||||
|
fnc: 'unbindAccount',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async test(e) {}
|
/**
|
||||||
|
* 登录命令入口
|
||||||
|
* @param e
|
||||||
|
* @returns {Promise<boolean>}
|
||||||
|
*/
|
||||||
|
async loginHandler(e) {
|
||||||
|
let config = await configControl.get();
|
||||||
|
if (!config?.login?.allowGroups.includes(e.group_id)) {
|
||||||
|
const img = await Meme.getMeme('zhenxun', 'default');
|
||||||
|
return e.reply(segment.img(img)); //都不在群里玩什么;[
|
||||||
|
}
|
||||||
|
const isAdmin = e.isAdmin;
|
||||||
|
const userId = e.user_id;
|
||||||
|
const match = e.msg.match(/^#登录(\d+)?$/);
|
||||||
|
let targetQq = match[1];
|
||||||
|
|
||||||
|
if (!targetQq) {
|
||||||
|
const binds = config?.login?.userBinds[userId] || [];
|
||||||
|
if (binds.length === 0) {
|
||||||
|
if (isAdmin) {
|
||||||
|
e.reply('请告诉我要登录的 QQ 号', true);
|
||||||
|
loginSessions.set(userId, { step: 'askQq', admin: true });
|
||||||
|
} else {
|
||||||
|
return e.reply('你没有绑定可登录的账号,请联系管理员分配..', true);
|
||||||
|
}
|
||||||
|
} else if (binds.length === 1) {
|
||||||
|
targetQq = binds[0];
|
||||||
|
} else {
|
||||||
|
e.reply(`你绑定了多个账号,请选择要登录的 QQ:\n${binds.join('\n')}`, true);
|
||||||
|
loginSessions.set(userId, { step: 'chooseQq', options: binds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
await this.startAdminLogin(e, targetQq);
|
||||||
|
} else {
|
||||||
|
const binds = config?.login?.userBinds[userId] || [];
|
||||||
|
if (!binds.includes(targetQq)) {
|
||||||
|
return e.reply('你没有权限登录该账号,请联系管理员分配', true);
|
||||||
|
}
|
||||||
|
await this.startUserLogin(e, targetQq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 管理员登录交互 */
|
||||||
|
async startAdminLogin(e, qq) {
|
||||||
|
loginSessions.set(e.user_id, {
|
||||||
|
step: 'askNickname',
|
||||||
|
qq,
|
||||||
|
admin: true,
|
||||||
|
});
|
||||||
|
e.reply(`请告诉我 QQ[${qq}] 的英文昵称`, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 普通用户登录 */
|
||||||
|
async startUserLogin(e, qq) {
|
||||||
|
loginSessions.set(e.user_id, {
|
||||||
|
step: 'askMethod',
|
||||||
|
qq,
|
||||||
|
admin: false,
|
||||||
|
});
|
||||||
|
e.reply(`请选择登录方式\nnc或lgr\n来登录 QQ[${qq}]`, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 绑定账号 */
|
||||||
|
async bindAccount(e) {
|
||||||
|
let config = await configControl.get()?.login;
|
||||||
|
if (!e.isAdmin) return;
|
||||||
|
const match = e.msg.match(/^#绑定账号\s+(\d+)$/);
|
||||||
|
if (!match) return;
|
||||||
|
const qq = match[1];
|
||||||
|
const at = e.at || e.user_id;
|
||||||
|
if (!config?.userBinds[at]) config.userBinds[at] = [];
|
||||||
|
if (!config?.userBinds[at].includes(qq)) {
|
||||||
|
config.userBinds[at].push(qq);
|
||||||
|
await ConfigControl.set('login', config);
|
||||||
|
e.reply(`已为 ${at} 绑定账号 ${qq}`, true);
|
||||||
|
} else {
|
||||||
|
e.reply(`该用户已绑定此账号`, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 解绑账号 */
|
||||||
|
async unbindAccount(e) {
|
||||||
|
if (!e.isAdmin) return false;
|
||||||
|
let config = await configControl.get()?.login;
|
||||||
|
const match = e.msg.match(/^#解绑账号\s+(\d+)$/);
|
||||||
|
if (!match) return;
|
||||||
|
const qq = match[1];
|
||||||
|
const at = e.at || e.user_id;
|
||||||
|
if (!config?.userBinds[at]) {
|
||||||
|
e.reply('该用户没有绑定账号', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
config.userBinds[at] = config.userBinds[at].filter((q) => q !== qq);
|
||||||
|
await ConfigControl.set('login', config);
|
||||||
|
e.reply(`已为 ${at} 解绑账号 ${qq}`, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 捕获消息继续交互 */
|
||||||
|
async accept(e) {
|
||||||
|
const session = loginSessions.get(e.user_id);
|
||||||
|
if (!session) return;
|
||||||
|
|
||||||
|
if (session.step === 'askQq') {
|
||||||
|
session.qq = e.msg.trim();
|
||||||
|
session.step = 'askNickname';
|
||||||
|
e.reply(`请告诉我 QQ[${session.qq}] 的英文昵称`, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.step === 'chooseQq') {
|
||||||
|
if (!session.options.includes(e.msg.trim())) {
|
||||||
|
e.reply('请选择列表中的 QQ', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session.qq = e.msg.trim();
|
||||||
|
session.step = 'askMethod';
|
||||||
|
e.reply(`请选择登录方式(回复 "nc" 或 "lgr")来登录 QQ[${session.qq}]`, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.step === 'askNickname') {
|
||||||
|
session.nickname = e.msg.trim();
|
||||||
|
session.step = 'askMethod';
|
||||||
|
e.reply('请选择登录方式(回复 "nc" 或 "lgr")', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.step === 'askMethod') {
|
||||||
|
const method = e.msg.trim().toLowerCase();
|
||||||
|
if (!['nc', 'lgr'].includes(method)) {
|
||||||
|
e.reply('登录方式无效,请回复 "nc" 或 "lgr"', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
session.method = method;
|
||||||
|
loginSessions.delete(e.user_id);
|
||||||
|
await this.doLogin(e, session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 执行登录 */
|
||||||
|
async doLogin(e, session) {
|
||||||
|
const { qq, method, nickname } = session;
|
||||||
|
e.reply(`开始使用 ${method} 登录 QQ[${qq}]`, true);
|
||||||
|
|
||||||
|
let loginInstance;
|
||||||
|
if (method === 'nc') {
|
||||||
|
loginInstance = NapcatService();
|
||||||
|
} else {
|
||||||
|
loginInstance = LgrService();
|
||||||
|
}
|
||||||
|
|
||||||
|
const qrPath = await loginInstance.login();
|
||||||
|
e.reply(segment.image(qrPath), true);
|
||||||
|
const timerKey = `login:timer:${qq}`;
|
||||||
|
redis.setex(timerKey, 120, 'pending');
|
||||||
|
|
||||||
|
const check = setInterval(async () => {
|
||||||
|
const status = await loginInstance.checkStatus();
|
||||||
|
if (status === 'success') {
|
||||||
|
clearInterval(check);
|
||||||
|
redis.del(timerKey);
|
||||||
|
e.reply(`QQ[${qq}] 登录成功!`, true);
|
||||||
|
}
|
||||||
|
const ttl = await redis.ttl(timerKey);
|
||||||
|
if (ttl <= 0) {
|
||||||
|
clearInterval(check);
|
||||||
|
await loginInstance.disconnect();
|
||||||
|
e.reply(`QQ[${qq}] 登录超时,已断开`, true);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
config/login.json
Normal file
4
config/login.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"allowGroups": [],
|
||||||
|
"userBinds": {}
|
||||||
|
}
|
||||||
25
lib/core/meme.js
Normal file
25
lib/core/meme.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import ConfigControl from '../config/configControl.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const Meme = {
|
||||||
|
/**
|
||||||
|
* 获取随机表情
|
||||||
|
* @param character 角色名称
|
||||||
|
* @param status 角色状态
|
||||||
|
* @returns {Promise<axios.AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
async getMeme(character, status) {
|
||||||
|
const coreConfig = await ConfigControl.get()?.coreConfig;
|
||||||
|
const coreUrl = coreConfig?.coreUrl;
|
||||||
|
const token = coreConfig?.token;
|
||||||
|
return await axios.get(`${coreUrl}/api/meme`, {
|
||||||
|
params: {
|
||||||
|
character: character,
|
||||||
|
status: status,
|
||||||
|
token: token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Meme;
|
||||||
Loading…
x
Reference in New Issue
Block a user