blog/source/_posts/userbot.md

213 lines
10 KiB
Markdown
Raw Normal View History

2023-01-20 03:29:32 +00:00
---
title: 从使用者和实用性角度出发谈 User Bot
date: 2023-01-20
# cover: https://pic.rmb.bdstatic.com/bjh/060df44eb7a12a6ae2fcd8f2ebcdbb3e.png
tags:
- Telegram
categories:
- 写 BUG 日常
- 野生技术协会
toc: true
---
我们真的需要一个 Telegram User Bot 吗?
<!--more-->
## 引言
今年 1 月份中下旬,因为原本 LittleSkin 运营组使用的 *Constance* 转发机器人年久失修,转发功能基本寄了,于是 *LittleSkinCommspt* 协助构建了一个新的 *QQ**Telegram* 之间相互转发的机器人,基于 [Clansty/Q2TG](https://github.com/Clansty/Q2TG)。后来因为种种原因,这个 Q2TG 无法再给社区使用,于是我就主动~~插手~~构建了一个新的 *Q2TG* 实例。
- **1 月 16 日** 注册了一个 `+1` 的 Telegram 账号作为 Q2TG 创建时注册的 User Bot在部署完成后我发现此 Telegram 账号立刻被封禁,但是 Q2TG 本身功能并没有发生影响,于是我就没太在意。
- **1 月 18 日** 在正常工作两天后的凌晨,我注意到机器人似乎出了故障,图片和表情均无法转发,这不免让我有些疑惑,于是我重新启动了 Docker 容器,然后就发现转发彻底寄了,一看后台,原来最让人担心的 User Bot 还是寄了,`USER_DEACTIVATED_BAN`Q2TG 报错,直接导致整个转发寄了。于是早上又尝试了 [`v1`](https://github.com/Clansty/Q2TG/tree/main) 版本,机器人勉强工作,也就继续用了。然后下午又注册了一个新的 `+1` 的 Telegram 账号,简单养了养号后又怀揣着忐忑的心情重新部署了一遍,然后我的 Telegram 账号就又寄了...
>我艹你喵杜叔叔,全家死光光!喵的!很明显这是中了杜叔叔的风控了,浪费了两个号...
## 看看 Issues 叭!
既然封了两次,我是不敢再拿我大号作死,于是我就打算看看 Issues 里面有没有人和我出现了一样的问题。
果不其然我就看到了~~在我之前尝试部署 Q2TG 的 [金姐姐](https://github.com/jinzhijie)~~ [Clansty/Q2TG#74](https://github.com/Clansty/Q2TG/issues/74) [Clansty/Q2TG#83](https://github.com/Clansty/Q2TG/issues/83)。一些人也是出现了无法登录 User Bot 的情况,也有人希望能禁用 User Bot。
但是 Issues 并没有帮我解决什么,但是至少知道了以下几点:
- User Bot 在 v1 中是作为类似于插件安装的,可以不进行配置
- User Bot 在群发功能中基本上只起到一个检测 Telegram 上消息撤回的功能
也就是说,按照现在的情况,如果我们可以舍弃检测 Telegram 上原生消息撤回,那 User Bot 模式确实有些没必要,毕竟部署的 Q2TG 是给 *LittleSkin* 的一系列群组使用的。
那有什么办法能去除 Q2TG 吗User Bot 模式已经写死在了代码里,那也就只能———
## 分析与修改代码
[Clansty/Q2TG](https://github.com/Clansty/Q2TG) 的最新版本 `v3`,也就是 `rainbowcat` 是基于 *TypeScript* 开发的。那就开始吧!但是从哪里开始呢?在随意翻看了几个文件后,我将视线锁定在了 `tgUser` 这个变量上。~~因为写的真的太明显了,简直就是一眼丁真。~~
于是我尝试在 GitHub 搜索了一下,没想到就可以直接开始肝了(
![](https://imgsrc.baidu.com/super/pic/item/377adab44aed2e739f6b04e9c201a18b86d6fa71.jpg)
分析了一下之后,我就打算开始着手删掉 `tgUser` 相关的内容。但在删到快一半的时候,我突然~~脑溢血地~~想到,如果我们在功能实现的部分保留所有的 `tgUser`,但是我们让他 `Undefined`,会不会就能直接非常方便地 disable 掉 User Bot 呢?(逃
然后我就真的大智若愚(大若智)地去试了。
很容易猜到 `tgUser` 应该是在机器人第一次配置的时候就被定义了,所以我就打算去 `SetupControlers.ts` 看看能不能在这里动动手脚,跳过里面地 User Bot 登录过程。
```ts SetupControlers>folded
import Telegram from '../client/Telegram';
import SetupService from '../services/SetupService';
import { Api } from 'telegram';
import { getLogger, Logger } from 'log4js';
import { Button } from 'telegram/tl/custom/button';
import setupHelper from '../helpers/setupHelper';
import commands from '../constants/commands';
import { WorkMode } from '../types/definitions';
import OicqClient from '../client/OicqClient';
import { md5Hex } from '../utils/hashing';
import Instance from '../models/Instance';
import db from '../models/db';
export default class SetupController {
private readonly setupService: SetupService;
private readonly log: Logger;
private isInProgress = false;
private waitForFinishCallbacks: Array<(ret: { tgUser: Telegram, oicq: OicqClient }) => unknown> = [];
// 创建的 UserBot
private tgUser: Telegram;
private oicq: OicqClient;
constructor(private readonly instance: Instance,
private readonly tgBot: Telegram) {
this.log = getLogger(`SetupController - ${instance.id}`);
this.setupService = new SetupService(this.instance, tgBot);
tgBot.addNewMessageEventHandler(this.handleMessage);
tgBot.setCommands(commands.preSetupCommands, new Api.BotCommandScopeUsers());
}
private handleMessage = async (message: Api.Message) => {
if (this.isInProgress || !message.isPrivate) {
return false;
}
if (message.text === '/setup' || message.text === '/start setup') {
this.isInProgress = true;
await this.doSetup(Number(message.sender.id));
await this.finishSetup();
return true;
}
return false;
};
private async doSetup(ownerId: number) {
// 设置 owner
try {
await this.setupService.claimOwner(ownerId);
}
catch (e) {
this.log.error('Claim Owner 失败', e);
this.isInProgress = false;
throw e;
}
// 设置工作模式
let workMode: WorkMode | '' = '';
try {
while (!workMode) {
const workModeText = await this.setupService.waitForOwnerInput('欢迎使用 Q2TG v2\n' +
'请选择工作模式,关于工作模式的区别请查看<a href="https://github.com/Clansty/Q2TG#%E5%85%B3%E4%BA%8E%E6%A8%A1%E5%BC%8F">这里</a>', [
[Button.text('个人模式', true, true)],
[Button.text('群组模式', true, true)],
]);
workMode = setupHelper.convertTextToWorkMode(workModeText);
}
this.setupService.setWorkMode(workMode);
}
catch (e) {
this.log.error('设置工作模式失败', e);
this.isInProgress = false;
throw e;
}
// 登录 oicq
try {
let uin = NaN;
while (isNaN(uin)) {
uin = Number(await this.setupService.waitForOwnerInput('请输入要登录 QQ 号'));
}
const platformText = await this.setupService.waitForOwnerInput('请选择登录协议', [
[Button.text('安卓手机', true, true)],
[Button.text('安卓平板', true, true)],
[Button.text('iPad', true, true)],
[Button.text('macOS', true, true)],
]);
const platform = setupHelper.convertTextToPlatform(platformText);
let password = await this.setupService.waitForOwnerInput('请输入密码', undefined, true);
password = md5Hex(password);
this.oicq = await this.setupService.createOicq(uin, password, platform);
this.instance.qqBotId = this.oicq.id;
await this.setupService.informOwner(`登录成功`);
}
catch (e) {
this.log.error('登录 OICQ 失败', e);
this.isInProgress = false;
throw e;
}
// 登录 tg UserBot
if (this.instance.userSessionId) {
await this.setupService.informOwner('userSessionId 已经存在,跳过');
}
else
try {
const phoneNumber = await this.setupService.waitForOwnerInput('创建 Telegram UserBot请输入你的手机号码需要带国家区号例如+86');
await this.setupService.informOwner('正在登录,请稍候…');
this.tgUser = await this.setupService.createUserBot(phoneNumber);
this.instance.userSessionId = this.tgUser.sessionId;
await this.setupService.informOwner(`登录成功`);
}
catch (e) {
this.log.error('创建 UserBot 失败', e);
this.isInProgress = false;
throw e;
}
}
private async finishSetup() {
this.tgBot.removeNewMessageEventHandler(this.handleMessage);
this.isInProgress = false;
await this.setupService.finishConfig();
this.waitForFinishCallbacks.forEach(e => e({
tgUser: this.tgUser,
oicq: this.oicq,
}));
}
public waitForFinish() {
return new Promise<{ tgUser: Telegram, oicq: OicqClient }>(resolve => {
this.waitForFinishCallbacks.push(resolve);
});
}
}
```
2023-01-20 03:55:21 +00:00
可以很清楚看到 *99 - 144* 行是注册 Telegram 的部分,那我们简单修改一下。
```diff 99 - 144
// 登录 tg UserBot
if (this.instance.userSessionId) {
await this.setupService.informOwner('userSessionId 已经存在,跳过');
}
- else
- try {
- const phoneNumber = await this.setupService.waitForOwnerInput('创建 Telegram UserBot请输入你的手机号码需要带国家区号例如+86');
- await this.setupService.informOwner('正在登录,请稍候…');
- this.tgUser = await this.setupService.createUserBot(phoneNumber);
- this.instance.userSessionId = this.tgUser.sessionId;
- await this.setupService.informOwner(`登录成功`);
- }
+ else {
+ await this.setupService.informOwner('Telegram User Bot 创建过程跳过');
+ }
catch (e) {
this.log.error('创建 UserBot 失败', e);
this.isInProgress = false;
throw e;
}
```
非常好,不是吗?于是我就乐呵的跑了 GitHub Actions 构建 Docker Image然后发现居然还真构建成功了于是我就更乐呵的去 `/setup` 我的机器人,没想到也正常跳过了!
2023-01-20 03:29:32 +00:00
2023-01-20 03:55:21 +00:00
当然这么改别的肯定是寄的,测试了一下转发功能完全废的。为什么相比也很清楚。~~你 `Undefined` 别的部分肯定不服会罢工啊!~~
2023-01-20 03:29:32 +00:00