/*! * @Author : Maraudern * @Date : 2023-01-16 20:19:47 * @LastEditors : 9Yan * @LastEditTime : 2023-05-12 20:58:43 * @FilePath : \Serein-Plugins\Serein\plugins\BetterWhitelist.js * @Description : 更好的白名单 */ /// /// /// @ts-check "use strict"; const FILE = importNamespace("System.IO").File; const DIRECTORY = importNamespace("System.IO").Directory; const ENCODING = importNamespace("System.Text").Encoding; const CONFIG_PATH = "plugins/BetterWhitelist/config.json"; const MEMBERS_PATH = "data/members.json"; const IS_GAME_ID = /^[0-9A-Za-z_ ]{3,16}$/; const IS_QQ_NUMBER = /^[0-9]{5,11}$/; const IS_CQ_AT = /^\[CQ:at,qq=(\d+)\]$/; const IS_PATH = /([^<>/\\\|:""\*\?]+)\.\w+$/; var whitelistPath, whitelist, config, members; var logger = new Logger("betterWhitelist"); var betterWhitelist = { name: "更好的白名单", version: "v1.8", author: "9Yan", description: "更完善的白名单管理方案,基于Serein成员管理,需禁用白名单相关正则", }; serein.registerPlugin(betterWhitelist.name, betterWhitelist.version, betterWhitelist.author, betterWhitelist.description); if (!DIRECTORY.Exists("plugins/BetterWhitelist")) { DIRECTORY.CreateDirectory("plugins/BetterWhitelist"); } if (!FILE.Exists(CONFIG_PATH)) { init(); logger.info("配置初始化成功"); } else { config = JSON.parse(FILE.ReadAllText(CONFIG_PATH)); logger.info("配置加载成功"); } if (config.version != betterWhitelist.version) { init(); logger.info("插件已更新,请重新进行配置"); } function init() { config = { NOTICE: "如何配置请查阅文档 https://market.serein.cc/resources/BetterWhitelistt#配置文件", version: betterWhitelist.version, ignoreGroup: [], hasBind: true, exitGroup: true, editCard: true, onlineMode: true, sendGroup: true, syncWhitelist: true, betterMembers: { enable: false, interServer: ["^.*?Player Spawned: (.*?) xuid:.*$", "^.*?Player connected: (.*?), xuid:.*$"], interServerReply: "^.*?Kicked (.*?) .*You do not have a whitelist!.*$", }, command: { bind: { name: "绑定", keywords: ["绑定", "bind"], }, unbind: { name: "解绑", keywords: ["解绑", "unbind"], }, whitelistAdd: { name: "添加白名单", keywords: ["添加白名单", "whitelistadd", "wladd"], }, whitelistDelete: { name: "删除白名单", keywords: ["删除白名单", "whitelistdelete", "wldel"], }, syncWhitelist: { name: "同步白名单", keywords: ["同步白名单", "whitelistsync", "wlsync"], }, whitelist: { name: "白名单列表", keywords: ["白名单列表", "whitelist", "wllist"], }, }, }; FILE.WriteAllText(CONFIG_PATH, JSON.stringify(config, null, 4)); } /** * @description: 在serein管理权限列表 * @param {Number} userID QQ号 * @return {Boolean} 是为true,否为false */ function hasPermission(userID) { return Boolean(serein.getSettingsObject().bot.permissionList.indexOf(userID) + 1); } /** * @description: 在serein监听群列表 * @param {Number} groupID QQ群号 * @return {Boolean} 是为true,否为false */ function isGroup(groupID) { return Boolean(serein.getSettingsObject().bot.groupList.indexOf(groupID) + 1); } /** * @description: 在serein成员管理列表 * @param {String} gameID 游戏ID * @return {Number} 是为数组下标,否为-1 */ function isMember(gameID) { members = JSON.parse(FILE.ReadAllText(MEMBERS_PATH, ENCODING.UTF8)); let data = -1; for (let i = 0; i < members.data.length; i++) { if (gameID === members.data[i].gameID) { data = i; break; } } return data; } /** * @description: 在betterWhitelist排除监听群列表 * @param {Number} groupID QQ群号 * @return {Boolean} 是为true,否为false */ function isIgnoreGroup(groupID) { return Boolean(config.ignoreGroup.indexOf(groupID) + 1); } /** * @description: 添加白名单 * @param {Number} groupID QQ群号 * @param {Number} userID QQ号 * @param {String} gameID 游戏ID * @return {Boolean} 成功为true,否则为false */ function whitelistAdd(groupID, userID, gameID) { if (config.syncWhitelist) { serein.sendCmd(`whitelist add "${gameID}"`); } if (config.editCard) { editCard(groupID, userID, gameID); } return serein.bindMember(userID, gameID); } /** * @description: 删除白名单 * @param {Number} userID QQ号 * @param {String} gameID 游戏ID * @return {Boolean} 成功为true,否则为false */ function whitelistRemove(userID, gameID) { serein.sendCmd(`whitelist remove "${gameID}"`); serein.sendCmd(`kick "${gameID}" You do not have a whitelist!`); return serein.unbindMember(userID); } /** * @description: 修改群昵称 * @param {Number} groupID QQ群号 * @param {Number} userID QQ号 * @param {String} card 群昵称 * @return {*} */ function editCard(groupID, userID, card) { serein.sendPacket( JSON.stringify({ action: "set_group_card", params: { group_id: groupID, user_id: userID, card: card, }, }) ); } /** * @description: 同步白名单 * @return {*} */ function syncWhitelist(groupID) { if (config.sendGroup) { serein.sendGroup(groupID, "正在同步白名单..."); } var errorWhitelist = []; var errorNumber = []; whitelistPath = serein.getSettingsObject().server.path.replace(IS_PATH, "allowlist.json"); if (!FILE.Exists(whitelistPath)) { whitelistPath = whitelistPath.replace(IS_PATH, "whitelist.json"); } whitelist = JSON.parse(FILE.ReadAllText(whitelistPath, ENCODING.UTF8)); members = JSON.parse(FILE.ReadAllText(MEMBERS_PATH, ENCODING.UTF8)); setTimeout(() => { var oldIds = whitelist.map((item) => item.name); var newIds = members.data.filter((item) => !oldIds.includes(item.gameID)); newIds.forEach((item) => { errorWhitelist.push(item.gameID); serein.sendCmd(`whitelist add "${item.gameID}"`); }); if (errorWhitelist.length) { let str = errorWhitelist.join(","); if (config.sendGroup) { serein.sendGroup(groupID, "添加白名单:\n" + str); } } var oldIds = members.data.map((item) => item.gameID); var newIds = whitelist.filter((item) => !oldIds.includes(item.name)); newIds.forEach((item) => { errorNumber.push(item.name); serein.sendCmd(`whitelist remove "${item.name}"`); }); if (errorNumber.length) { let str = errorNumber.join(","); if (config.sendGroup) { serein.sendGroup(groupID, "删除白名单:\n" + str); } } if (!errorWhitelist.length && !errorNumber.length && config.sendGroup) { serein.sendGroup(groupID, "没有需要同步的白名单"); } }, 1000); return; } serein.setListener("onReceiveGroupMessage", (groupID, userID, msg, shownName) => { if (!isGroup(groupID) || isIgnoreGroup(groupID)) return; let command = msg.split(" ").filter((item) => item && item.trim()); let keyword = command[0].toLowerCase(); command.splice(0, 1); let keywords = []; for (let key in config.command) { if (config.command.hasOwnProperty(key)) { keywords = keywords.concat(config.command[key].keywords); } } for (let i in keywords) { if (keyword.indexOf(keywords[i]) === 0 && keyword !== keywords[i]) { if (config.sendGroup) { serein.sendGroup(groupID, `关键词>>${keywords[i]}<<后需要添加空格`); } return; } } //绑定 if (config.command.bind.keywords.includes(keyword)) { if (!hasPermission(userID) && !config.hasBind) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } if (!command.length) { if (config.sendGroup) { serein.sendGroup(groupID, `语法错误,请发送:\n${keyword} `); } return; } var text = command.join(" "); if (config.onlineMode && !IS_GAME_ID.test(text)) { if (config.sendGroup) { serein.sendGroup(groupID, `意外的:>>${text}<<\n应当为:`); } return; } var index = isMember(text); if (index + 1) { if (config.sendGroup) { serein.sendGroup(groupID, `绑定失败,存在相同\n${text}(${members.data[index].id})`); } return; } var gameID = serein.getGameID(userID); if (gameID) { whitelistRemove(userID, gameID); if (whitelistAdd(groupID, userID, text) && config.sendGroup) serein.sendGroup(groupID, `已存在数据:\n${gameID}(${userID})\n成功修改为:\n${text}(${userID})`); return; } if (whitelistAdd(groupID, userID, text)) { if (config.sendGroup) { serein.sendGroup(groupID, `绑定成功:${text}(${userID})`); } } else { serein.sendGroup(groupID, `绑定失败,原因未知!\n(可联系插件作者反馈问题)`); } return; } //解绑 if (config.command.unbind.keywords.includes(keyword)) { if (!hasPermission(userID) && !config.hasBind) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } var gameID = serein.getGameID(userID); if (!gameID) { if (config.sendGroup) { serein.sendGroup(groupID, "您没有绑定!"); } return; } if (whitelistRemove(userID, gameID)) { if (config.sendGroup) { serein.sendGroup(groupID, `解绑成功:${gameID}(${userID})`); } } else { serein.sendGroup(groupID, `解绑失败,原因未知!\n(可联系插件作者反馈问题)`); } return; } //添加白名单 if (config.command.whitelistAdd.keywords.includes(keyword)) { if (!hasPermission(userID)) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } if (!command.length) { if (config.sendGroup) { serein.sendGroup(groupID, `语法错误,请发送:\n ${keyword} `); } return; } if (!IS_QQ_NUMBER.test(command[0].replace(IS_CQ_AT, "$1"))) { if (config.sendGroup) { serein.sendGroup(groupID, `意外的:>>${command[0].replace(IS_CQ_AT, "$1")}<<\n应当为:`); } return; } var qqID = Number(command[0].replace(IS_CQ_AT, "$1")); command.splice(0, 1); var text = command.join(" "); if (config.onlineMode && !IS_GAME_ID.test(text)) { if (config.sendGroup) { serein.sendGroup(groupID, `意外的:>>${text}<<\n应当为:`); } return; } var index = isMember(text); if (index + 1) { if (config.sendGroup) { serein.sendGroup(groupID, `添加白名单失败,存在相同\n${text}(${members.data[index].id})`); } return; } var gameID = serein.getGameID(qqID); if (gameID) { whitelistRemove(qqID, gameID); if (whitelistAdd(groupID, qqID, text) && config.sendGroup) { serein.sendGroup(groupID, `已存在数据:\n${gameID}(${qqID})\n成功修改为:\n${text}(${qqID})`); } return; } if (whitelistAdd(groupID, qqID, text)) { if (config.sendGroup) { serein.sendGroup(groupID, `添加白名单成功:${text}(${qqID})`); } } else { serein.sendGroup(groupID, `添加白名单失败,原因未知!\n(可联系插件作者反馈问题)`); } return; } //删除白名单 if (config.command.whitelistDelete.keywords.includes(keyword)) { if (!hasPermission(userID)) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } if (!command.length) { if (config.sendGroup) { serein.sendGroup(groupID, `语法错误,请发送:\n${keyword} `); } return; } if (!IS_QQ_NUMBER.test(command[0].replace(IS_CQ_AT, "$1"))) { if (config.sendGroup) { serein.sendGroup(groupID, `意外的:>>${command[0].replace(IS_CQ_AT, "$1")}<<\n应当为:`); } return; } var qqID = Number(command[0].replace(IS_CQ_AT, "$1")); var gameID = serein.getGameID(qqID); if (!gameID) { if (config.sendGroup) { serein.sendGroup(groupID, `该成员未绑定 `); } return; } if (whitelistRemove(qqID, gameID)) { if (config.sendGroup) { serein.sendGroup(groupID, `成功删除:${gameID}(${qqID})`); } } else { serein.sendGroup(groupID, `删除白名单失败,原因未知!\n(可联系插件作者反馈问题)`); } return; } //同步白名单 if (config.command.syncWhitelist.keywords.includes(keyword)) { if (!hasPermission(userID)) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } if (!command.length) { syncWhitelist(groupID); return; } if (!IS_QQ_NUMBER.test(command[0].replace(IS_CQ_AT, "$1"))) { if (config.sendGroup) { serein.sendGroup(groupID, `意外的:>>${command[0].replace(IS_CQ_AT, "$1")}<<\n应当为:`); } return; } var qqID = Number(command[0].replace(IS_CQ_AT, "$1")); var gameID = serein.getGameID(qqID); if (!gameID) { if (config.sendGroup) { serein.sendGroup(groupID, `该成员未绑定 `); } return; } serein.sendCmd(`whitelist add "${gameID}"`); if (config.sendGroup) { serein.sendGroup(groupID, `白名单同步成功:${gameID}(${qqID})`); } return; } //白名单列表 if (config.command.whitelist.keywords.includes(keyword)) { if (!hasPermission(userID)) { if (config.sendGroup) { serein.sendGroup(groupID, `您没有使用<${keyword}>的权限!`); } return; } whitelistPath = serein.getSettingsObject().server.path.replace(IS_PATH, "allowlist.json"); if (!FILE.Exists(whitelistPath)) { whitelistPath = whitelistPath.replace(IS_PATH, "whitelist.json"); } whitelist = JSON.parse(FILE.ReadAllText(whitelistPath, ENCODING.UTF8)); members = JSON.parse(FILE.ReadAllText(MEMBERS_PATH, ENCODING.UTF8)); var Array = []; for (let i = 0; i < members.data.length; i++) { let isCorrect = "❗"; for (let j = 0; j < whitelist.length; j++) { if (members.data[i].gameID === whitelist[j].name) { isCorrect = "✔"; } } let isName = members.data[i].card ? members.data[i].card : members.data[i].nickname ? members.data[i].nickname : members.data[i].ID; Array.push({ type: "node", data: { name: "『" + i + "』" + isName, uin: members.data[i].id, content: "成员管理数据:\n" + members.data[i].gameID + "(" + members.data[i].id + ")\n服务器白名单:" + isCorrect, }, }); } if (config.sendGroup) { while (Array.length > 90) { serein.sendPacket( '{"action": "send_group_forward_msg","params": {"group_id": "' + groupID + '","messages": ' + JSON.stringify(Array.splice(0, 90)) + "}}" ); } serein.sendPacket('{"action": "send_group_forward_msg","params": {"group_id": "' + groupID + '","messages": ' + JSON.stringify(Array) + "}}"); } return; } }); serein.setListener("onServerStart", () => { if (!config.syncWhitelist) return; for (let i = 0; i < serein.getSettingsObject().bot.groupList.length; i++) { if (!isIgnoreGroup(serein.getSettingsObject().bot.groupList[i])) { var groupID = serein.getSettingsObject().bot.groupList[i]; break; } } syncWhitelist(groupID); }); serein.setListener("onGroupDecrease", (groupID, userID) => { if (!config.exitGroup || !isGroup(groupID) || isIgnoreGroup(groupID)) return; if (config.sendGroup) { serein.sendGroup(groupID, "群成员 " + userID + " 退群了,尝试删除白名单"); } let gameID = serein.getGameID(userID); if (!gameID) { if (config.sendGroup) { serein.sendGroup(groupID, "群成员 " + userID + " 未绑定白名单!"); } return; } if (whitelistRemove(userID, gameID)) { setTimeout(() => { if (config.sendGroup) { serein.sendGroup(groupID, `成功删除:${gameID}(${userID})`); } }, 500); } else { serein.sendGroup(groupID, `删除白名单失败,原因未知!\n(可联系插件作者反馈问题)`); } return; }); serein.setListener("onServerOutput", (msg) => { if (!config.betterMembers.enable) return; let gameID, gameIDReply; let interServerReply = new RegExp(config.betterMembers.interServerReply); if (interServerReply.test(msg)) { gameIDReply = msg.replace(interServerReply, "$1"); let index = 0; while (index !== -1) { index = notGameID.indexOf(gameIDReply); if (index > -1) { notGameID.splice(index, 1); } } } for (let i = 0; i < config.betterMembers.interServer.length; i++) { let interServer = new RegExp(config.betterMembers.interServer[i]); if (interServer.test(msg)) { gameID = msg.replace(interServer, "$1"); } } if (!gameID) return; members = JSON.parse(FILE.ReadAllText(MEMBERS_PATH, ENCODING.UTF8)); for (let i = 0; i < members.data.length; i++) { if (members.data[i].gameID === gameID) return; } if (notGameID.indexOf(gameID) == -1) { notGameID.push(gameID); for (let i = 0; i < serein.getSettingsObject().bot.groupList.length; i++) { if (!isIgnoreGroup(serein.getSettingsObject().bot.groupList[i])) { var groupID = serein.getSettingsObject().bot.groupList[i]; break; } } setTimeout(() => { serein.sendGroup(groupID, gameID + " 没有白名单,踢出服务器"); }, 500); } }); var notGameID = []; setInterval(() => { for (let i = 0; i < notGameID.length; i++) { serein.sendCmd('kick "' + notGameID[i] + '" You do not have a whitelist!'); } }, 1000);