From 60552ff07dd92ab02a87ec4e0975a4af08eb63f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Thu, 6 Oct 2022 12:37:10 +0800 Subject: [PATCH] fix cbq permission & add more cbq engine --- engine.go | 130 +++++++++++++++++++- event.go | 4 +- matcher.go | 7 +- rules.go | 346 ++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 387 insertions(+), 100 deletions(-) diff --git a/engine.go b/engine.go index 3a35d73..b6b9909 100644 --- a/engine.go +++ b/engine.go @@ -242,7 +242,7 @@ func OnMessageKeyword(keyword string, rules ...Rule) *Matcher { return defaultEngine.OnMessageKeyword(keyword, rules...) } -// OnKeyword 关键词触发器 +// OnMessageKeyword 关键词触发器 func (e *Engine) OnMessageKeyword(keyword string, rules ...Rule) *Matcher { matcher := &Matcher{ Type: "Message", @@ -365,6 +365,43 @@ func (e *Engine) OnMessageShell(command string, model interface{}, rules ...Rule return StoreMatcher(matcher) } +// OnCallbackQueryPrefix 前缀触发器 +func OnCallbackQueryPrefix(prefix string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryPrefix(prefix, rules...) +} + +// OnCallbackQueryPrefix 前缀触发器 +func (e *Engine) OnCallbackQueryPrefix(prefix string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{PrefixRule(prefix)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQuerySuffix 后缀触发器 +func OnCallbackQuerySuffix(suffix string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQuerySuffix(suffix, rules...) +} + +// OnCallbackQuerySuffix 后缀触发器 +func (e *Engine) OnCallbackQuerySuffix(suffix string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{SuffixRule(suffix)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQueryRegex 正则触发器 +func OnCallbackQueryRegex(regexPattern string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryRegex(regexPattern, rules...) +} + // OnCallbackQueryRegex 正则触发器 func (e *Engine) OnCallbackQueryRegex(regexPattern string, rules ...Rule) *Matcher { matcher := &Matcher{ @@ -375,3 +412,94 @@ func (e *Engine) OnCallbackQueryRegex(regexPattern string, rules ...Rule) *Match e.matchers = append(e.matchers, matcher) return StoreMatcher(matcher) } + +// OnCallbackQueryKeyword 关键词触发器 +func OnCallbackQueryKeyword(keyword string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryKeyword(keyword, rules...) +} + +// OnCallbackQueryKeyword 关键词触发器 +func (e *Engine) OnCallbackQueryKeyword(keyword string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{KeywordRule(keyword)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQueryFullMatch 完全匹配触发器 +func OnCallbackQueryFullMatch(src string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryFullMatch(src, rules...) +} + +// OnCallbackQueryFullMatch 完全匹配触发器 +func (e *Engine) OnCallbackQueryFullMatch(src string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{FullMatchRule(src)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQueryFullMatchGroup 完全匹配触发器组 +func OnCallbackQueryFullMatchGroup(src []string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryFullMatchGroup(src, rules...) +} + +// OnCallbackQueryFullMatchGroup 完全匹配触发器组 +func (e *Engine) OnCallbackQueryFullMatchGroup(src []string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{FullMatchRule(src...)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQueryKeywordGroup 关键词触发器组 +func OnCallbackQueryKeywordGroup(keywords []string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryKeywordGroup(keywords, rules...) +} + +// OnCallbackQueryKeywordGroup 关键词触发器组 +func (e *Engine) OnCallbackQueryKeywordGroup(keywords []string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{KeywordRule(keywords...)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQueryPrefixGroup 前缀触发器组 +func (e *Engine) OnCallbackQueryPrefixGroup(prefix []string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{PrefixRule(prefix...)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} + +// OnCallbackQuerySuffixGroup 后缀触发器组 +func OnCallbackQuerySuffixGroup(suffix []string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQuerySuffixGroup(suffix, rules...) +} + +// OnCallbackQuerySuffixGroup 后缀触发器组 +func (e *Engine) OnCallbackQuerySuffixGroup(suffix []string, rules ...Rule) *Matcher { + matcher := &Matcher{ + Type: "CallbackQuery", + Rules: append([]Rule{SuffixRule(suffix...)}, rules...), + Engine: e, + } + e.matchers = append(e.matchers, matcher) + return StoreMatcher(matcher) +} diff --git a/event.go b/event.go index 0ec243c..577539a 100644 --- a/event.go +++ b/event.go @@ -73,7 +73,7 @@ func (tc *TelegramClient) processEvent(update tgba.Update) { } func match(ctx *Ctx, matchers []*Matcher) { - if ctx.Message != nil { + if ctx.Message != nil && ctx.Event.Type == "Message" { // Caption也当作消息处理 if ctx.Message.Text == "" && ctx.Message.Caption != "" { ctx.Message.Text = ctx.Message.Caption @@ -81,7 +81,7 @@ func match(ctx *Ctx, matchers []*Matcher) { log.Println("cpoy Message Caption to Text:", ctx.Message.Text) } } - if ctx.Message != nil && ctx.Message.Text != "" { // 确保无空 + if ctx.Message != nil && ctx.Event.Type == "Message" && ctx.Message.Text != "" { // 确保无空 ctx.IsToMe = func(ctx *Ctx) bool { if ctx.Message.Chat.IsPrivate() { log.Debugln("[event] private event") diff --git a/matcher.go b/matcher.go index c356b11..2e869bc 100644 --- a/matcher.go +++ b/matcher.go @@ -65,23 +65,28 @@ func (m *Matcher) setPriority(priority int) *Matcher { return m } +/* // firstPriority 设置当前 Matcher 优先级 - 0 func (m *Matcher) firstPriority() *Matcher { return m.setPriority(0) } +*/ // secondPriority 设置当前 Matcher 优先级 - 1 func (m *Matcher) secondPriority() *Matcher { return m.setPriority(1) } +/* // thirdPriority 设置当前 Matcher 优先级 - 2 func (m *Matcher) thirdPriority() *Matcher { return m.setPriority(2) } +*/ // Limit 限速器 -// postfn 当请求被拒绝时的操作 +// +// postfn 当请求被拒绝时的操作 func (m *Matcher) Limit(limiterfn func(*Ctx) *rate.Limiter, postfn ...func(*Ctx)) *Matcher { m.Rules = append(m.Rules, func(ctx *Ctx) bool { if limiterfn(ctx).Acquire() { diff --git a/rules.go b/rules.go index 1fa1df4..d2cb648 100644 --- a/rules.go +++ b/rules.go @@ -15,19 +15,36 @@ import ( // 检查消息前缀 func PrefixRule(prefixes ...string) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.Text == "" { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.Text == "" { // 确保无空 + return false + } + for _, prefix := range prefixes { + if strings.HasPrefix(msg.Text, prefix) { + ctx.State["prefix"] = prefix + arg := strings.TrimLeft(msg.Text[len(prefix):], " ") + ctx.State["args"] = arg + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.Data == "" { + return false + } + for _, prefix := range prefixes { + if strings.HasPrefix(msg.Data, prefix) { + ctx.State["prefix"] = prefix + arg := strings.TrimLeft(msg.Data[len(prefix):], " ") + ctx.State["args"] = arg + return true + } + } + return false + default: return false } - for _, prefix := range prefixes { - if strings.HasPrefix(msg.Text, prefix) { - ctx.State["prefix"] = prefix - arg := strings.TrimLeft(msg.Text[len(prefix):], " ") - ctx.State["args"] = arg - return true - } - } - return false } } @@ -36,23 +53,42 @@ func PrefixRule(prefixes ...string) Rule { // 检查消息后缀 func SuffixRule(suffixes ...string) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.Text == "" { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.Text == "" { // 确保无空 + return false + } + for _, suffix := range suffixes { + if strings.HasSuffix(msg.Text, suffix) { + ctx.State["suffix"] = suffix + arg := strings.TrimRight(msg.Text[:len(msg.Text)-len(suffix)], " ") + ctx.State["args"] = arg + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.Data == "" { + return false + } + for _, suffix := range suffixes { + if strings.HasSuffix(msg.Data, suffix) { + ctx.State["suffix"] = suffix + arg := strings.TrimRight(msg.Data[:len(msg.Data)-len(suffix)], " ") + ctx.State["args"] = arg + return true + } + } + return false + default: return false } - for _, suffix := range suffixes { - if strings.HasSuffix(msg.Text, suffix) { - ctx.State["suffix"] = suffix - arg := strings.TrimRight(msg.Text[:len(msg.Text)-len(suffix)], " ") - ctx.State["args"] = arg - return true - } - } - return false } } // CommandRule check if the message is a command and trim the command name +// +// this rule only supports tgba.Message func CommandRule(commands ...string) Rule { return func(ctx *Ctx) bool { msg, ok := ctx.Value.(*tgba.Message) @@ -123,6 +159,8 @@ func RegexRule(regexPattern string) Rule { } // ReplyRule check if the message is replying some message +// +// this rule only supports tgba.Message func ReplyRule(messageID int) Rule { return func(ctx *Ctx) bool { msg, ok := ctx.Value.(*tgba.Message) @@ -136,38 +174,70 @@ func ReplyRule(messageID int) Rule { // KeywordRule check if the message has a keyword or keywords func KeywordRule(src ...string) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.Text == "" { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.Text == "" { // 确保无空 + return false + } + for _, str := range src { + if strings.Contains(msg.Text, str) { + ctx.State["keyword"] = str + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.Data == "" { + return false + } + for _, str := range src { + if strings.Contains(msg.Data, str) { + ctx.State["keyword"] = str + return true + } + } + return false + default: return false } - for _, str := range src { - if strings.Contains(msg.Text, str) { - ctx.State["keyword"] = str - return true - } - } - return false } } // FullMatchRule check if src has the same copy of the message func FullMatchRule(src ...string) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.Text == "" { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.Text == "" { // 确保无空 + return false + } + for _, str := range src { + if str == msg.Text { + ctx.State["matched"] = msg.Text + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.Data == "" { + return false + } + for _, str := range src { + if str == msg.Data { + ctx.State["matched"] = msg.Data + return true + } + } + return false + default: return false } - for _, str := range src { - if str == msg.Text { - ctx.State["matched"] = msg.Text - return true - } - } - return false } } // ShellRule 定义shell-like规则 +// +// this rule only supports tgba.Message func ShellRule(cmd string, model interface{}) Rule { cmdRule := CommandRule(cmd) t := reflect.TypeOf(model) @@ -190,6 +260,8 @@ func ShellRule(cmd string, model interface{}) Rule { } // OnlyToMe only triggered in conditions of @bot or begin with the nicknames +// +// this rule only supports tgba.Message func OnlyToMe(ctx *Ctx) bool { return ctx.IsToMe } @@ -197,32 +269,60 @@ func OnlyToMe(ctx *Ctx) bool { // CheckUser only triggered by specific person func CheckUser(userId ...int64) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.From == nil { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.From == nil { // 确保无空 + return false + } + for _, uid := range userId { + if msg.From.ID == uid { + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.From == nil { + return false + } + for _, uid := range userId { + if msg.From.ID == uid { + return true + } + } + return false + default: return false } - for _, uid := range userId { - if msg.From.ID == uid { - return true - } - } - return false } } // CheckChat only triggered in specific chat func CheckChat(chatId ...int64) Rule { return func(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.Chat == nil { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.Chat == nil { // 确保无空 + return false + } + for _, cid := range chatId { + if msg.Chat.ID == cid { + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.Message == nil || msg.Message.Chat == nil { + return false + } + for _, cid := range chatId { + if msg.Message.Chat.ID == cid { + return true + } + } + return false + default: return false } - for _, cid := range chatId { - if msg.Chat.ID == cid { - return true - } - } - return false } } @@ -273,66 +373,116 @@ func OnlyChannel(ctx *Ctx) bool { // SuperUserPermission only triggered by the bot's owner func SuperUserPermission(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.From == nil { // 确保无空 + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.From == nil { // 确保无空 + return false + } + for _, su := range ctx.Caller.b.SuperUsers { + if su == msg.From.ID { + return true + } + } + return false + case *tgba.CallbackQuery: + if msg.From == nil { + return false + } + for _, su := range ctx.Caller.b.SuperUsers { + if su == msg.From.ID { + return true + } + } + return false + default: return false } - for _, su := range ctx.Caller.b.SuperUsers { - if su == msg.From.ID { - return true - } - } - return false } // CreaterPermission only triggered by the group creater or higher permission func CreaterPermission(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.From == nil || msg.Chat == nil { // 确保无空 - return false + if SuperUserPermission(ctx) { + return true } - for _, su := range ctx.Caller.b.SuperUsers { - if su == msg.From.ID { - return true + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.From == nil || msg.Chat == nil { // 确保无空 + return false } - } - m, err := ctx.Caller.GetChatMember( - tgba.GetChatMemberConfig{ - ChatConfigWithUser: tgba.ChatConfigWithUser{ - ChatID: msg.Chat.ID, - UserID: msg.From.ID, + m, err := ctx.Caller.GetChatMember( + tgba.GetChatMemberConfig{ + ChatConfigWithUser: tgba.ChatConfigWithUser{ + ChatID: msg.Chat.ID, + UserID: msg.From.ID, + }, }, - }, - ) - if err != nil { + ) + if err != nil { + return false + } + return m.IsCreator() + case *tgba.CallbackQuery: + if msg.From == nil || msg.Message == nil || msg.Message.Chat == nil { + return false + } + m, err := ctx.Caller.GetChatMember( + tgba.GetChatMemberConfig{ + ChatConfigWithUser: tgba.ChatConfigWithUser{ + ChatID: msg.Message.Chat.ID, + UserID: msg.From.ID, + }, + }, + ) + if err != nil { + return false + } + return m.IsCreator() + default: return false } - return m.IsCreator() } // AdminPermission only triggered by the group admins or higher permission func AdminPermission(ctx *Ctx) bool { - msg, ok := ctx.Value.(*tgba.Message) - if !ok || msg.From == nil || msg.Chat == nil { // 确保无空 - return false + if SuperUserPermission(ctx) { + return true } - for _, su := range ctx.Caller.b.SuperUsers { - if su == msg.From.ID { - return true + switch msg := ctx.Value.(type) { + case *tgba.Message: + if msg.From == nil || msg.Chat == nil { // 确保无空 + return false } - } - m, err := ctx.Caller.GetChatMember( - tgba.GetChatMemberConfig{ - ChatConfigWithUser: tgba.ChatConfigWithUser{ - ChatID: msg.Chat.ID, - UserID: msg.From.ID, + m, err := ctx.Caller.GetChatMember( + tgba.GetChatMemberConfig{ + ChatConfigWithUser: tgba.ChatConfigWithUser{ + ChatID: msg.Chat.ID, + UserID: msg.From.ID, + }, }, - }, - ) - if err != nil { + ) + if err != nil { + return false + } + return m.IsCreator() || m.IsAdministrator() + case *tgba.CallbackQuery: + if msg.From == nil || msg.Message == nil || msg.Message.Chat == nil { + return false + } + m, err := ctx.Caller.GetChatMember( + tgba.GetChatMemberConfig{ + ChatConfigWithUser: tgba.ChatConfigWithUser{ + ChatID: msg.Message.Chat.ID, + UserID: msg.From.ID, + }, + }, + ) + if err != nil { + return false + } + return m.IsCreator() || m.IsAdministrator() + default: return false } - return m.IsCreator() || m.IsAdministrator() } // UserOrGrpAdmin 允许用户单独使用或群管使用 @@ -344,6 +494,8 @@ func UserOrGrpAdmin(ctx *Ctx) bool { } // IsPhoto 消息是图片返回 true +// +// this rule only supports tgba.Message func IsPhoto(ctx *Ctx) bool { msg, ok := ctx.Value.(*tgba.Message) if !ok || len(msg.Photo) == 0 { // 确保无空 @@ -354,6 +506,8 @@ func IsPhoto(ctx *Ctx) bool { } // MustProvidePhoto 消息不存在图片阻塞120秒至有图片,超时返回 false +// +// this rule only supports tgba.Message func MustProvidePhoto(needphohint, failhint string) Rule { return func(ctx *Ctx) bool { msg, ok := ctx.Value.(*tgba.Message)