diff --git a/apps/login.js b/apps/login.js index c8bd9b2..9509b68 100644 --- a/apps/login.js +++ b/apps/login.js @@ -1,15 +1,15 @@ 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'; import NapcatService from '../lib/login/napcat.js'; import LgrService from '../lib/login/lgr.js'; const configPath = path.join(process.cwd(), 'data/crystelf/config'); const loginSessions = new Map(); //正在进行的登录会话 +const bindSessions = new Map(); //正在进行的绑定会话 +const activeLogins = new Map(); //在线登录实例 export default class LoginService extends plugin { constructor() { @@ -24,13 +24,17 @@ export default class LoginService extends plugin { fnc: 'loginHandler', }, { - reg: '^#绑定账号\\s+\\d+$', + reg: '^#绑定账号(\\s+\\d+)?$', fnc: 'bindAccount', }, { reg: '^#解绑账号\\s+\\d+$', fnc: 'unbindAccount', }, + { + reg: '^#退出登录\\s+\\d+$', + fnc: 'logoutHandler', + }, ], }); } @@ -54,17 +58,15 @@ export default class LoginService extends plugin { if (!targetQq) { const binds = config?.login?.userBinds[userId] || []; if (binds.length === 0) { - if (isAdmin) { - loginSessions.set(userId, { step: 'askQq', admin: true }); - return e.reply('你想登哪个qq?', true); - } else { - return e.reply('管理员似乎没有给你分配可用账户,请联系管理员添加..', true); - } + return e.reply('管理员似乎没有给你分配可用账户,请联系管理员添加..', true); } else if (binds.length === 1) { - targetQq = binds[0]; + targetQq = binds[0].qq; } else { loginSessions.set(userId, { step: 'chooseQq', options: binds }); - return e.reply(`你小子账号还挺多,选一个qq登录吧:\n${binds.join('\n')}`, true); + return e.reply( + `你小子账号还挺多,选一个qq登录吧:\n${binds.map((b) => b.qq).join('\n')}`, + true + ); } } @@ -72,10 +74,11 @@ export default class LoginService extends plugin { await this.startAdminLogin(e, targetQq); } else { const binds = config?.login?.userBinds[userId] || []; - if (!binds.includes(targetQq)) { + const bind = binds.find((b) => b.qq === targetQq); + if (!bind) { return e.reply('你没有权限登录该账号,请联系管理员分配..', true); } - await this.startUserLogin(e, targetQq); + await this.startUserLogin(e, bind); } } @@ -97,16 +100,22 @@ export default class LoginService extends plugin { /** * 普通用户 * @param e - * @param qq + * @param bind * @returns {Promise<*>} */ - async startUserLogin(e, qq) { + async startUserLogin(e, bind) { loginSessions.set(e.user_id, { - step: 'askMethod', - qq, + step: 'autoLogin', + qq: bind.qq, + nickname: bind.nickname, + method: bind.method, admin: false, }); - return e.reply(`请选择登录方式\nnc或lgr\n来登录 QQ[${qq}]`, true); + return this.doLogin(e, { + qq: bind.qq, + nickname: bind.nickname, + method: bind.method, + }); } /** @@ -115,23 +124,13 @@ export default class LoginService extends plugin { * @returns {Promise<*>} */ async bindAccount(e) { - let config = await configControl.get()?.login; if (!e.isMaster) { const img = await Meme.getMeme('zhenxun', 'default'); return e.reply(segment.image(img)); } - 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); - return e.reply(`已为 ${at} 绑定账号 ${qq}`, true); - } else { - return e.reply(`该用户已绑定此账号`, true); - } + bindSessions.set(e.user_id, { step: 'askQq', targetUser: at }); + return e.reply('要绑定的QQ号是哪个?', true); } /** @@ -150,14 +149,38 @@ export default class LoginService extends plugin { const qq = match[1]; const at = e.at || e.user_id; if (!config?.userBinds[at]) { - ``; - return e.reply('该用户没有绑定账号', true); + return e.reply('该用户没有绑定账号..', true); } - config.userBinds[at] = config.userBinds[at].filter((q) => q !== qq); + config.userBinds[at] = config.userBinds[at].filter((q) => q.qq !== qq); await ConfigControl.set('login', config); return e.reply(`已为 ${at} 解绑账号 ${qq}`, true); } + /** + * 退出登录 + * @param e + * @returns {Promise<*>} + */ + async logoutHandler(e) { + const match = e.msg.match(/^#退出登录\s+(\d+)$/); + if (!match) return; + const qq = match[1]; + const instance = activeLogins.get(qq); + if (!instance) { + return e.reply(`QQ[${qq}] 没有活跃的登录会话..`, true); + } + let config = await configControl.get(); + const isAdmin = e.isMaster; + const userId = e.user_id; + const binds = config?.login?.userBinds[userId] || []; + if (!isAdmin && !binds.includes(qq)) { + return e.reply(`你没有权限退出 QQ[${qq}] 的会话..`, true); + } + await instance.disconnect(); + activeLogins.delete(qq); + return e.reply(`QQ[${qq}] 已退出登录..`, true); + } + /** * 登录流程 * @param e @@ -165,42 +188,76 @@ export default class LoginService extends plugin { */ async accept(e) { const session = loginSessions.get(e.user_id); - if ( - !session || - !e.group_id || - !(await ConfigControl.get()?.login?.allowGroups.includes(e.group_id)) - ) - return; + const bindSession = bindSessions.get(e.user_id); + if (!session && !bindSession) return; - if (session.step === 'askQq') { - session.qq = e.msg.trim(); - session.step = 'askNickname'; - return e.reply(`QQ[${session.qq}]的英文名叫什么?`, true); - } - - if (session.step === 'chooseQq') { - if (!session.options.includes(e.msg.trim())) { - return e.reply('请选择列表中的 QQ', true); + if (bindSession) { + if (bindSession.step === 'askQq') { + bindSession.qq = e.msg.trim(); + bindSession.step = 'askNickname'; + return e.reply(`QQ[${bindSession.qq}]的英文名叫什么?`, true); } - session.qq = e.msg.trim(); - session.step = 'askMethod'; - return e.reply(`请选择登录方式\n[nc]或[lgr]\n来登录 QQ[${session.qq}]`, true); - } - - if (session.step === 'askNickname') { - session.nickname = e.msg.trim(); - session.step = 'askMethod'; - return e.reply(`请选择登录方式\n[nc]或[lgr]\n来登录 QQ[${session.qq}]`, true); - } - - if (session.step === 'askMethod') { - const method = e.msg.trim().toLowerCase(); - if (!['nc', 'lgr'].includes(method)) { - return e.reply('登录方式无效', true); + if (bindSession.step === 'askNickname') { + bindSession.nickname = e.msg.trim(); + bindSession.step = 'askMethod'; + return e.reply(`请选择登录方式\n[nc]或[lgr]\n来绑定 QQ[${bindSession.qq}]`, true); + } + if (bindSession.step === 'askMethod') { + const method = e.msg.trim().toLowerCase(); + if (!['nc', 'lgr'].includes(method)) { + return e.reply('登录方式无效', true); + } + bindSession.method = method; + let config = await configControl.get()?.login; + if (!config.userBinds[bindSession.targetUser]) + config.userBinds[bindSession.targetUser] = []; + config.userBinds[bindSession.targetUser].push({ + qq: bindSession.qq, + nickname: bindSession.nickname, + method: bindSession.method, + }); + await ConfigControl.set('login', config); + bindSessions.delete(e.user_id); + return e.reply( + `已为 ${bindSession.targetUser} 绑定账号 ${bindSession.qq} (${bindSession.nickname}, ${bindSession.method})`, + true + ); + } + } + + if (session) { + let config = await configControl.get(); + if (!e.group_id || !config?.login?.allowGroups.includes(e.group_id)) return; + + if (session.step === 'chooseQq') { + const chosen = e.msg.trim(); + const bind = session.options.find((b) => b.qq === chosen); + if (!bind) { + return e.reply('请选择列表中的 QQ', true); + } + loginSessions.delete(e.user_id); + return this.doLogin(e, { + qq: bind.qq, + nickname: bind.nickname, + method: bind.method, + }); + } + + if (session.step === 'askNickname') { + session.nickname = e.msg.trim(); + session.step = 'askMethod'; + return e.reply(`请选择登录方式\n[nc]或[lgr]\n来登录 QQ[${session.qq}]`, true); + } + + if (session.step === 'askMethod') { + const method = e.msg.trim().toLowerCase(); + if (!['nc', 'lgr'].includes(method)) { + return e.reply('登录方式无效', true); + } + session.method = method; + loginSessions.delete(e.user_id); + await this.doLogin(e, session); } - session.method = method; - loginSessions.delete(e.user_id); - await this.doLogin(e, session); } } @@ -220,6 +277,7 @@ export default class LoginService extends plugin { } else { loginInstance = new LgrService(); } + activeLogins.set(qq, loginInstance); const qrPath = await loginInstance.login(qq, nickname); const loginTimers = new Map(); if (qrPath && qrPath !== 'none') { @@ -243,6 +301,7 @@ export default class LoginService extends plugin { clearInterval(check); loginTimers.delete(timerKey); await loginInstance.disconnect(nickname); + activeLogins.delete(qq); return e.reply(`QQ[${qq}] 登录超时,已断开,请重新发起登录..`, true); }, 120 * 1000); const timerObj = { check, timeout };