Skip to content

Commit

Permalink
update adblock
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashang committed Jun 1, 2022
1 parent 0e2805e commit 0a79189
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 41 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ runtime/
dist/
config.toml
db/geecaptcha.db
captcha-bot
captcha-bot
dict/dec_*
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ Telegram Api文档:[Telegram Api](https://core.telegram.org/bots/api)
下载:
```shell
# 下载项目
git clone https://github.com/assimon/captcha-bot && cd captcha-bot && cp .env.example .env
git clone https://github.com/assimon/captcha-bot && cd captcha-bot
```
编译:
```shell
# 编译
go build -o cbot
go build -o captcha-bot
# 给予执行权限
chmod +x ./cbot
chmod +x ./captcha-bot
```
配置:
```shell
Expand All @@ -48,32 +48,44 @@ cp .example.config.toml config.toml
执行:
```shell
# 调试启动
./cbot
./captcha-bot
# nohup
nohup ./cbot >> run.log 2>&1 &
nohup ./captcha-bot >> run.log 2>&1 &
```

### 二、下载已经编译好的二进制程序
此方式可以直接使用,用于服务器生产环境。
进入打包好的版本列表,下载程序:[https://github.com/assimon/captcha-bot/releases](https://github.com/assimon/captcha-bot/releases)
配置:
```shell
cp .env.example .env
cp .example.config.toml config.toml
```
运行:
```shell
# linux
# 调试启动
./captcha-bot
# nohup 常驻启动

# windows
captcha-bot.exe
```

## 配置:
请将项目目录下`.env.example`文件重命名为`.env`, 然后对`.env`文件进行编辑即可!
里面的配置项有详细的注释。
### 三、机器人命令
```
/ping #存活检测,机器人若正常将返回"pong"
# 广告相关
/add_ad #新增一条广告,格式:广告标题|跳转链接|到期时间(带时分秒)|权重(倒序,值越大越靠前),例如:/add_ad 📢广告招租|https://google.com|2099-01-01 00:00:00|100
/all_ad #查看所有广告
/del_ad #删除一条广告,例如:/del_ad 1(删除id为1的广告)
```

### 四、敏感词词库使用
在项目`dict`文件夹提供了一些敏感词库,用于机器人反垃圾功能。由于不可描述原因词库不能`明文`放置于项目仓库。
如需使用,请使用`openssl`命令进行解密,且文件名必须以`dec_`开头,否则无法正常加载!
例如:
```shell
openssl enc -d -aes256 -pass pass:captcha-bot -in dict/enc_dc1.txt -out dict/dec_dc1.txt
```

## 预览
![禁言.png](https://i.loli.net/2021/09/27/dZQSFKmI23nbXhN.png)
Expand Down
2 changes: 2 additions & 0 deletions bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/assimon/captcha-bot/util/config"
"github.com/assimon/captcha-bot/util/log"
"github.com/assimon/captcha-bot/util/orm"
"github.com/assimon/captcha-bot/util/sensitiveword"
"os"
"os/signal"
"syscall"
Expand All @@ -15,6 +16,7 @@ func Start() {
config.InitConfig()
log.InitLog()
orm.InitDb()
sensitiveword.InitSensitiveWord()
// 机器人启动
go func() {
defer func() {
Expand Down
Binary file added dict/enc_dc1.txt
Binary file not shown.
Binary file added dict/enc_dc2.txt
Binary file not shown.
22 changes: 14 additions & 8 deletions example.config.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#系统设置
[system]
join_hint_after_del_time=60 #加群验证提示消息多久删除,秒
captcha_timeout=120 #验证超时时间,秒
runtime_path="/runtime"
join_hint_after_del_time=60 # 加群验证提示消息多久删除,秒
captcha_timeout=120 # 验证超时时间,秒
runtime_path="/runtime" # 缓存目录

#telegram 配置
[telegram]
bot_token=""
api_proxy=""
manage_users=[]
bot_token="" # 机器人apitoken
api_proxy="" # telegram api代理,仅大陆地区服务器需要
manage_users=[] # 超级管理员userid数组,以英文逗号分割,例如123,456,789

#日志配置
[log]
Expand All @@ -18,6 +18,12 @@ max_backups=3

#消息模板
[message]
join_hint="欢迎 @%s 加入 %s\n\n本群已开启新成员验证功能,未通过验证的用户无法发言\n\n⏱本条消息 %d 秒后自动删除\n\n👇点击下方按钮自助解除禁言"
join_hint="欢迎 [%s](%s) 加入 %s\n\n️本群已开启新成员验证功能,未通过验证的用户无法发言 \n\n⏱本条消息 %d 秒后自动删除\n\n👇点击下方按钮自助解除禁言"
captcha_image="欢迎您加入[%s]!\n\n⚠本群已开启新成员验证功能。\n\n👆为了证明您不是机器人,请发送以上图片验证码内容\n\n🤖机器人将自动验证您发送的验证码内容是否正确\n\n⏱本条验证消息有效期[%d]秒"
verification_complete="恭喜您成功通过[🤖人机验证],系统已为您解除禁言限制。\n\n如若还是无法发言,请重启telegram客户端"
verification_complete="恭喜您成功通过[🤖人机验证],系统已为您解除禁言限制。\n\n如若还是无法发言,请重启telegram客户端"
block_hint="\\#封禁预警\n[%s](%s) 请注意,您的消息中含有部分违禁词 \n⚠️您已被系统判断为高风险用户,已被封禁\n系统已向超管发送预警信息,若由超管判定为误杀,会及时将您解除封禁。\n您的违禁词包含:%s"

#广告阻止
[adblock]
number_of_forbidden_words=2 # 违禁词判定个数,如果一句话中出现的违禁词为该设置个数,则判断为违禁
block_time=-1 # 阻止时间,单位:秒。如果为-1,则代表永久封禁
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/importcjj/sensitive v0.0.0-20200106142752-42d1c505be7b // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/magiconair/properties v1.8.6 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/importcjj/sensitive v0.0.0-20200106142752-42d1c505be7b h1:9hudrgWUhyfR4FRMOfL9KB1uYw48DUdHkkgr9ODOw7Y=
github.com/importcjj/sensitive v0.0.0-20200106142752-42d1c505be7b/go.mod h1:zLVdX6Ed2SvCbEamKmve16U0E03UkdJo4ls1TBfmc8Q=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
Expand Down
7 changes: 5 additions & 2 deletions service/AdvertiseService.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@ import (
"github.com/golang-module/carbon/v2"
)

// AddAdvertiseService 新增广告
func AddAdvertiseService(advertise model.Advertise) (err error) {
return orm.Gdb.Model(&advertise).Create(&advertise).Error
}

// AllAdvertiseService 加载所有广告
func AllAdvertiseService() (advertises []model.Advertise, err error) {
err = orm.Gdb.Model(&advertises).Find(&advertises).Error
return
}

// GetEfficientAdvertiseService 加载正在生效的广告
func GetEfficientAdvertiseService() (advertises []model.Advertise, err error) {
nowTime := carbon.Now().Timestamp()
err = orm.Gdb.Model(&advertises).Where("validity_period > ?", nowTime).Order("sort desc").Find(&advertises).Error
err = orm.Gdb.Model(&advertises).Where("validity_period > ?", carbon.Now().Timestamp()).Order("sort desc").Find(&advertises).Error
return
}

// DeleteAdvertiseService 删除一条广告
func DeleteAdvertiseService(id int64) (err error) {
return orm.Gdb.Where("id = ?", id).Delete(&model.Advertise{}).Error
}
110 changes: 92 additions & 18 deletions telegram/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/assimon/captcha-bot/util/captcha"
"github.com/assimon/captcha-bot/util/config"
"github.com/assimon/captcha-bot/util/log"
"github.com/assimon/captcha-bot/util/sensitiveword"
"github.com/golang-module/carbon/v2"
uuid "github.com/satori/go.uuid"
tb "gopkg.in/telebot.v3"
Expand All @@ -25,6 +26,7 @@ var (

var (
captchaMessageMenu = &tb.ReplyMarkup{ResizeKeyboard: true}
manslaughterMenu = &tb.ReplyMarkup{ResizeKeyboard: true}
)

var (
Expand Down Expand Up @@ -101,7 +103,7 @@ func StartCaptcha(c tb.Context) error {
userCaptchaCodeKey := strconv.FormatInt(userId, 10)
gUserCaptchaCodeTable.Set(userCaptchaCodeKey, userCaptchaCodeVal)
time.AfterFunc(time.Duration(config.SystemC.CaptchaTimeout)*time.Second, func() {
os.Remove(imgUrl)
_ = os.Remove(imgUrl)
gMessageTokenMap.Delete(chatToken)
gUserCaptchaCodeTable.Del(userCaptchaCodeKey)
err = Bot.Delete(botMsg)
Expand All @@ -114,10 +116,73 @@ func StartCaptcha(c tb.Context) error {

// OnTextMessage 文本消息
func OnTextMessage(c tb.Context) error {
// 不是私聊
if !c.Message().Private() {
// 私聊走入群验证操作
if c.Message().Private() {
return VerificationProcess(c)
}
// 否则走广告阻止监听
return AdBlock(c)
}

// AdBlock 广告阻止
func AdBlock(c tb.Context) error {
userId := c.Message().Sender.ID
userLink := fmt.Sprintf("tg://user?id=%d", c.Message().Sender.ID)
userNickname := c.Message().Sender.LastName + c.Message().Sender.FirstName
messageText := c.Message().Text
// 管理员 放行任何操作
if isManage(c.Chat(), userId) {
return nil
}
dict := sensitiveword.Filter.FindAll(messageText)
if len(dict) <= 0 || len(dict) < config.AdBlockC.NumberOfForbiddenWords {
return nil
}
// ban user
restrictedUntil := config.AdBlockC.BlockTime
if restrictedUntil <= 0 {
restrictedUntil = tb.Forever()
}
err := Bot.Restrict(c.Chat(), &tb.ChatMember{
Rights: tb.NoRights(),
User: c.Message().Sender,
RestrictedUntil: restrictedUntil,
})
if err != nil {
log.Sugar.Error("[AdBlock] ban user err:", err)
return err
}
blockMessage := fmt.Sprintf(config.MessageC.BlockHint,
userNickname,
userLink,
strings.Join(dict, ","))
manslaughterBtn := manslaughterMenu.Data("👮🏻管理员解封", strconv.FormatInt(userId, 10))
manslaughterMenu.Inline(manslaughterMenu.Row(manslaughterBtn))
Bot.Handle(&manslaughterBtn, func(c tb.Context) error {
if err = Bot.Delete(c.Message()); err != nil {
log.Sugar.Error("[AdBlock] delete adblock message err:", err)
return err
}
// 解禁用户
err = Bot.Restrict(c.Chat(), &tb.ChatMember{
User: &tb.User{ID: userId},
Rights: tb.NoRestrictions(),
})
if err != nil {
log.Sugar.Error("[AdBlock] unban user err:", err)
return err
}
return c.Send(fmt.Sprintf("管理员已解除对用户:[%s](%s) 的封禁", userNickname, userLink), tb.ModeMarkdownV2)
}, isManageMiddleware)
if err = c.Reply(blockMessage, manslaughterMenu, tb.ModeMarkdownV2); err != nil {
log.Sugar.Error("[AdBlock] reply message err:", err)
return err
}
return c.Delete()
}

// VerificationProcess 验证处理
func VerificationProcess(c tb.Context) error {
userIdStr := strconv.FormatInt(c.Sender().ID, 10)
captchaCode := gUserCaptchaCodeTable.Get(userIdStr)
if captchaCode == nil || captchaCode.UserId != c.Sender().ID {
Expand All @@ -140,17 +205,20 @@ func OnTextMessage(c tb.Context) error {
gUserCaptchaCodeTable.Del(userIdStr)
gUserCaptchaPendingTable.Del(fmt.Sprintf("%d|%d", captchaCode.PendingMessage.ID, captchaCode.PendingMessage.Chat.ID))
//删除验证消息
Bot.Delete(captchaCode.CaptchaMessage)
Bot.Delete(captchaCode.PendingMessage)
if err = Bot.Delete(captchaCode.CaptchaMessage); err != nil {
log.Sugar.Error("[OnTextMessage] delete captcha message err:", err)
}
if err = Bot.Delete(captchaCode.PendingMessage); err != nil {
log.Sugar.Error("[OnTextMessage] delete pending message err:", err)
}
return c.Send(config.MessageC.VerificationComplete)

}

// UserJoinGroup 用户加群事件
func UserJoinGroup(c tb.Context) error {
var err error
err = c.Delete()
if err != nil {

if err = c.Delete(); err != nil {
log.Sugar.Error("[UserJoinGroup] delete join message err:", err)
}
// 如果是管理员邀请的,直接通过
Expand All @@ -166,10 +234,14 @@ func UserJoinGroup(c tb.Context) error {
if err != nil {
log.Sugar.Error("[UserJoinGroup] ban user err:", err)
}
joinMessage := fmt.Sprintf(config.MessageC.JoinHint, c.Message().UserJoined.Username, c.Chat().Title, config.SystemC.JoinHintAfterDelTime)
userLink := fmt.Sprintf("tg://user?id=%d", c.Message().UserJoined.ID)
joinMessage := fmt.Sprintf(config.MessageC.JoinHint,
c.Message().UserJoined.LastName+c.Message().UserJoined.FirstName,
userLink,
c.Chat().Title,
config.SystemC.JoinHintAfterDelTime)
chatToken := uuid.NewV4().String()
doCaptchaBtn := joinMessageMenu.URL("👉🏻点我开始人机验证🤖", fmt.Sprintf("https://t.me/%s?start=%s", Bot.Me.Username, chatToken))

joinMessageMenu.Inline(
joinMessageMenu.Row(doCaptchaBtn),
joinMessageMenu.Row(manageBanBtn, managePassBtn),
Expand All @@ -191,7 +263,7 @@ func UserJoinGroup(c tb.Context) error {
if err != nil {
log.Sugar.Error("[UserJoinGroup] add captcha record err:", err)
}
captchaMessage, err := Bot.Send(c.Chat(), joinMessage, joinMessageMenu)
captchaMessage, err := Bot.Send(c.Chat(), joinMessage, joinMessageMenu, tb.ModeMarkdownV2)
if err != nil {
log.Sugar.Error("[UserJoinGroup] send join hint message err:", err)
}
Expand All @@ -206,8 +278,7 @@ func UserJoinGroup(c tb.Context) error {
captchaDataKey := fmt.Sprintf("%d|%d", captchaMessage.ID, c.Chat().ID)
gUserCaptchaPendingTable.Set(captchaDataKey, captchaDataVal)
time.AfterFunc(time.Duration(config.SystemC.JoinHintAfterDelTime)*time.Second, func() {
err = Bot.Delete(captchaMessage)
if err != nil {
if err = Bot.Delete(captchaMessage); err != nil {
log.Sugar.Error("[UserJoinGroup] delete join hint message err:", err)
}
})
Expand Down Expand Up @@ -279,7 +350,7 @@ func refreshCaptcha() func(c tb.Context) error {
}
captchaCode.Code = code
gUserCaptchaCodeTable.Set(userIdStr, captchaCode)
os.Remove(imgUrl)
_ = os.Remove(imgUrl)
return c.Respond(&tb.CallbackResponse{
Text: "验证码已刷新~",
})
Expand Down Expand Up @@ -307,7 +378,9 @@ func AddAd(c tb.Context) error {
if err != nil {
return c.Send("新增广告失败:" + err.Error())
}
c.Send("新增广告成功")
if err = c.Send("新增广告成功"); err != nil {
log.Sugar.Error("[AddAd] send success message err:", err)
}
return AllAd(c)
}

Expand Down Expand Up @@ -339,10 +412,11 @@ func DelAd(c tb.Context) error {
if err != nil {
return c.Send(err.Error())
}
err = service.DeleteAdvertiseService(id)
if err != nil {
if err = service.DeleteAdvertiseService(id); err != nil {
return c.Send(err.Error())
}
c.Send("广告删除成功!")
if err = c.Send("广告删除成功!"); err != nil {
log.Sugar.Error("[DelAd] send success message err:", err)
}
return AllAd(c)
}
5 changes: 3 additions & 2 deletions telegram/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ func RegisterHandle() {
Bot.Handle(START_CMD, StartCaptcha)
Bot.Handle(tb.OnUserJoined, UserJoinGroup)
Bot.Handle(tb.OnText, OnTextMessage)
Bot.Handle(&manageBanBtn, ManageBan(), isManageMiddleware)
Bot.Handle(&managePassBtn, ManagePass(), isManageMiddleware)
Bot.Handle(tb.OnUserLeft, func(c tb.Context) error {
return c.Delete()
})
// 按钮点击事件
Bot.Handle(&manageBanBtn, ManageBan(), isManageMiddleware)
Bot.Handle(&managePassBtn, ManagePass(), isManageMiddleware)
// 广告
Bot.Handle(ADD_AD, AddAd, isRootMiddleware)
Bot.Handle(ALL_AD, AllAd, isRootMiddleware)
Expand Down
Loading

0 comments on commit 0a79189

Please sign in to comment.