✏️ drop all pb & 增加 gist 审批

This commit is contained in:
fumiama 2021-12-16 15:27:47 +08:00
parent a363623df9
commit e2c603338e
11 changed files with 209 additions and 196 deletions

View File

@ -91,11 +91,12 @@ zerobot -h -t token -u url [-d|w] [-g 监听地址:端口] qq1 qq2 qq3 ...
- [x] 列出所有提醒 - [x] 列出所有提醒
- [x] 翻牌 - [x] 翻牌
- [x] [开启|关闭]入群验证 - [x] [开启|关闭]入群验证
- [ ] 同意入群请求 - [x] [开启|关闭]gist加群自动审批
- [ ] 同意好友请求 - [ ] 同意好友请求
- [ ] 撤回[@xxx] [xxx] - [ ] 撤回[@xxx] [xxx]
- [ ] 警告[@xxx] - [ ] 警告[@xxx]
- [x] run[xxx] - [x] run[xxx]
- 注使用gist加群自动审批请在群介绍添加以下说明同时开启`需要回答问题并由管理员审核`加群请在github新建一个gist其文件名为本群群号的字符串的md5内容为一行是当前unix时间戳。然后请将您的用户名和gist哈希按照username/gisthash的格式填写到回答即可。
- **GitHub仓库搜索** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_github"` - **GitHub仓库搜索** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin_github"`
- [x] >github [xxx] - [x] >github [xxx]
- [x] >github -p [xxx] - [x] >github -p [xxx]

2
go.mod
View File

@ -6,7 +6,6 @@ require (
github.com/FloatTech/AnimeAPI v1.1.10 github.com/FloatTech/AnimeAPI v1.1.10
github.com/FloatTech/ZeroBot-Plugin-Gif v0.2.4 github.com/FloatTech/ZeroBot-Plugin-Gif v0.2.4
github.com/FloatTech/bot-manager v1.0.1-0.20211112011524-85b9895271ed github.com/FloatTech/bot-manager v1.0.1-0.20211112011524-85b9895271ed
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737
github.com/corona10/goimagehash v1.0.3 github.com/corona10/goimagehash v1.0.3
github.com/fogleman/gg v1.3.0 github.com/fogleman/gg v1.3.0
github.com/fumiama/cron v1.3.0 github.com/fumiama/cron v1.3.0
@ -24,6 +23,5 @@ require (
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
github.com/tidwall/gjson v1.12.1 github.com/tidwall/gjson v1.12.1
github.com/wdvxdr1123/ZeroBot v1.4.1 github.com/wdvxdr1123/ZeroBot v1.4.1
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 golang.org/x/image v0.0.0-20211028202545-6944b10bf410
) )

2
go.sum
View File

@ -12,8 +12,6 @@ github.com/FloatTech/imgfactory v0.1.1/go.mod h1:ThDALab8aOuU6KVYESVWFqmjcqtm03e
github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb h1:Rkj28fqIwGx/EgBzRYtpmJRfH6wqVn7cNdc7aJ0QE4M= github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb h1:Rkj28fqIwGx/EgBzRYtpmJRfH6wqVn7cNdc7aJ0QE4M=
github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb/go.mod h1:imVKbfKqqeit+C/eaWGb4MKQ3z3gN6pRpBU5RMtp5so= github.com/Mrs4s/MiraiGo v0.0.0-20211120033824-43b23f4e6fcb/go.mod h1:imVKbfKqqeit+C/eaWGb4MKQ3z3gN6pRpBU5RMtp5so=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737 h1:p4o7/eSoP39jwnGZz08N1IpH/mNzg9SdCn7kPM9A9BE=
github.com/RomiChan/protobuf v0.0.0-20211204042931-ff4f35848737/go.mod h1:CKKOWC7mBxd36zxsCB1V8DTrwlTNRQvkSVbYqyUiGEE=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M=

View File

@ -1,68 +0,0 @@
package main
import (
"crypto/md5"
"encoding/binary"
"fmt"
"os"
"github.com/RomiChan/protobuf/proto"
"github.com/wdvxdr1123/ZeroBot/utils/helper"
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
)
type Composition struct {
Array []string `protobuf:"bytes,1,rep"`
}
var (
compo Composition
)
type Text struct {
Id int64 `db:"id"`
Data string `db:"data"`
}
func main() {
err := LoadText(os.Args[1])
if err == nil {
arrl := len(compo.Array)
fmt.Printf("[Diana]读取%d条小作文\n", arrl)
db := sql.Sqlite{DBPath: os.Args[2]}
err = db.Create("text", &Text{})
if err != nil {
panic(err)
}
for _, d := range compo.Array {
s := md5.Sum(helper.StringToBytes(d))
i := int64(binary.LittleEndian.Uint64(s[:8]))
fmt.Printf("[Diana]id: %d\n", i)
err = db.Insert("text", &Text{
Id: i,
Data: d,
})
if err != nil {
panic(err)
}
c, _ := db.Count("text")
fmt.Println("[Diana]转化", c, "条小作文")
}
err = db.Close()
if err != nil {
panic(err)
}
} else {
panic(err)
}
}
// LoadText 加载小作文
func LoadText(pbfile string) error {
data, err := os.ReadFile(pbfile)
if err != nil {
return err
}
return proto.Unmarshal(data, &compo)
}

43
plugin_manager/gist.go Normal file
View File

@ -0,0 +1,43 @@
package manager
import (
"crypto/md5"
"encoding/hex"
"fmt"
"strconv"
"time"
"github.com/FloatTech/ZeroBot-Plugin/utils/math"
"github.com/FloatTech/ZeroBot-Plugin/utils/web"
"github.com/sirupsen/logrus"
"github.com/wdvxdr1123/ZeroBot/utils/helper"
)
// user hash file
const gistraw = "https://gist.githubusercontent.com/%s/%s/raw/%s"
func checkNewUser(qq, gid int64, ghun, hash string) (bool, string) {
if db.CanFind("member", "where ghun="+ghun) {
return false, "该github用户已入群"
}
gidsum := md5.Sum(helper.StringToBytes(strconv.FormatInt(gid, 10)))
gidhex := hex.EncodeToString(gidsum[:])
u := fmt.Sprintf(gistraw, ghun, hash, gidhex)
logrus.Debugln("[gist]visit url:", u)
data, err := web.GetData(u)
if err == nil {
logrus.Debugln("[gist]get data:", helper.BytesToString(data))
st, err := strconv.ParseInt(helper.BytesToString(data), 10, 64)
if err == nil {
// 600s 内验证成功
ok := math.Abs(int(time.Now().Unix()-st)) < 600
if ok {
_ = db.Insert("member", &Member{QQ: qq, Ghun: ghun})
return true, ""
}
return false, "时间戳超时"
}
return false, "时间戳格式错误: " + helper.BytesToString(data)
}
return false, "无法连接到gist: " + err.Error()
}

View File

@ -0,0 +1,12 @@
package manager
type Welcome struct {
GrpID int64 `db:"gid"`
Msg string `db:"msg"`
}
type Member struct {
QQ int64 `db:"qq"`
// github username
Ghun string `db:"ghun"`
}

View File

@ -3,15 +3,12 @@ package manager
import ( import (
"fmt" "fmt"
"io"
"math/rand" "math/rand"
"os"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/RomiChan/protobuf/proto"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/rate" "github.com/wdvxdr1123/ZeroBot/extension/rate"
@ -19,14 +16,14 @@ import (
"github.com/FloatTech/ZeroBot-Plugin/control" "github.com/FloatTech/ZeroBot-Plugin/control"
"github.com/FloatTech/ZeroBot-Plugin/plugin_manager/timer" "github.com/FloatTech/ZeroBot-Plugin/plugin_manager/timer"
"github.com/FloatTech/ZeroBot-Plugin/utils/file"
"github.com/FloatTech/ZeroBot-Plugin/utils/math" "github.com/FloatTech/ZeroBot-Plugin/utils/math"
"github.com/FloatTech/ZeroBot-Plugin/utils/process"
"github.com/FloatTech/ZeroBot-Plugin/utils/sql"
) )
const ( const (
datapath = "data/manager/" datapath = "data/manager/"
confile = datapath + "config.pb" confile = datapath + "config.db"
timerfile = datapath + "timers.pb"
hint = "====群管====\n" + hint = "====群管====\n" +
"- 禁言@QQ 1分钟\n" + "- 禁言@QQ 1分钟\n" +
"- 解除禁言 @QQ\n" + "- 解除禁言 @QQ\n" +
@ -55,20 +52,22 @@ const (
) )
var ( var (
config Config db = &sql.Sqlite{DBPath: confile}
limit = rate.NewManager(time.Minute*5, 2) limit = rate.NewManager(time.Minute*5, 2)
clock timer.Clock clock timer.Clock
) )
var engine = control.Register("manager", &control.Options{ var engine = control.Register("manager", &control.Options{
DisableOnDefault: false, DisableOnDefault: false,
Help: hint, Help: hint,
}) })
func init() { // 插件主体 func init() { // 插件主体
loadConfig()
go func() { go func() {
time.Sleep(time.Second + time.Millisecond*time.Duration(rand.Intn(1000))) process.SleepAbout1sTo2s()
clock = timer.NewClock(timerfile) clock = timer.NewClock(db)
db.Create("welcome", &Welcome{})
db.Create("member", &Member{})
}() }()
// 升为管理 // 升为管理
engine.OnRegex(`^升为管理.*?(\d+)`, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).SetPriority(40). engine.OnRegex(`^升为管理.*?(\d+)`, zero.OnlyGroup, zero.SuperUserPermission).SetBlock(true).SetPriority(40).
@ -363,14 +362,17 @@ func init() { // 插件主体
engine.OnNotice().SetBlock(false).FirstPriority(). engine.OnNotice().SetBlock(false).FirstPriority().
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
if ctx.Event.NoticeType == "group_increase" && ctx.Event.SelfID != ctx.Event.UserID { if ctx.Event.NoticeType == "group_increase" && ctx.Event.SelfID != ctx.Event.UserID {
word, ok := config.Welcome[ctx.Event.GroupID] var w Welcome
if ok { err := db.Find("welcome", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
ctx.SendChain(message.Text(word)) if err == nil {
ctx.SendChain(message.Text(w.Msg))
} else { } else {
ctx.SendChain(message.Text("欢迎~")) ctx.SendChain(message.Text("欢迎~"))
} }
enable, ok1 := config.Checkin[ctx.Event.GroupID] c, ok := control.Lookup("manager")
if ok1 && enable { if ok {
enable := c.GetData(ctx.Event.GroupID)&1 == 1
if enable {
uid := ctx.Event.UserID uid := ctx.Event.UserID
a := rand.Intn(100) a := rand.Intn(100)
b := rand.Intn(100) b := rand.Intn(100)
@ -406,6 +408,7 @@ func init() { // 插件主体
} }
} }
} }
}
}) })
// 退群提醒 // 退群提醒
engine.OnNotice().SetBlock(false).SetPriority(40). engine.OnNotice().SetBlock(false).SetPriority(40).
@ -419,30 +422,66 @@ func init() { // 插件主体
// 设置欢迎语 // 设置欢迎语
engine.OnRegex(`^设置欢迎语([\s\S]*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40). engine.OnRegex(`^设置欢迎语([\s\S]*)$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
config.Welcome[ctx.Event.GroupID] = ctx.State["regex_matched"].([]string)[1] w := &Welcome{
if saveConfig() == nil { GrpID: ctx.Event.GroupID,
Msg: ctx.State["regex_matched"].([]string)[1],
}
err := db.Insert("welcome", w)
if err == nil {
ctx.SendChain(message.Text("记住啦!")) ctx.SendChain(message.Text("记住啦!"))
} else { } else {
ctx.SendChain(message.Text("出错啦!")) ctx.SendChain(message.Text("出错啦: ", err))
} }
}) })
// 入群验证开关 // 入群验证开关
engine.OnRegex(`^(.*)入群验证$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40). engine.OnRegex(`^(.*)入群验证$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
option := ctx.State["regex_matched"].([]string)[1] option := ctx.State["regex_matched"].([]string)[1]
c, ok := control.Lookup("manager")
if ok {
data := c.GetData(ctx.Event.GroupID)
switch option { switch option {
case "开启": case "开启", "打开", "启用":
config.Checkin[ctx.Event.GroupID] = true data |= 1
case "关闭": case "关闭", "关掉", "禁用":
config.Checkin[ctx.Event.GroupID] = false data &= 0x7fffffff_fffffffe
default: default:
return return
} }
if saveConfig() == nil { err := c.SetData(ctx.Event.GroupID, data)
if err == nil {
ctx.SendChain(message.Text("已", option)) ctx.SendChain(message.Text("已", option))
} else { return
ctx.SendChain(message.Text("出错啦!"))
} }
ctx.SendChain(message.Text("出错啦: ", err))
return
}
ctx.SendChain(message.Text("找不到服务!"))
})
// 加群 gist 验证开关
engine.OnRegex(`^(.*)gist加群自动审批$`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).SetPriority(40).
Handle(func(ctx *zero.Ctx) {
option := ctx.State["regex_matched"].([]string)[1]
c, ok := control.Lookup("manager")
if ok {
data := c.GetData(ctx.Event.GroupID)
switch option {
case "开启", "打开", "启用":
data |= 0x10
case "关闭", "关掉", "禁用":
data &= 0x7fffffff_fffffffd
default:
return
}
err := c.SetData(ctx.Event.GroupID, data)
if err == nil {
ctx.SendChain(message.Text("已", option))
return
}
ctx.SendChain(message.Text("出错啦: ", err))
return
}
ctx.SendChain(message.Text("找不到服务!"))
}) })
// 运行 CQ 码 // 运行 CQ 码
engine.OnRegex(`^run(.*)$`, zero.SuperUserPermission).SetBlock(true).SetPriority(0). engine.OnRegex(`^run(.*)$`, zero.SuperUserPermission).SetBlock(true).SetPriority(0).
@ -453,61 +492,33 @@ func init() { // 插件主体
// 可注入,权限为主人 // 可注入,权限为主人
ctx.Send(cmd) ctx.Send(cmd)
}) })
// 自动同意加好友,被邀请入群(从qingyunke移过来先注释) // 根据 gist 自动同意加群
/* // 加群请在github新建一个gist其文件名为本群群号的字符串的md5内容为一行是当前unix时间戳。
// 然后请将您的用户名和gist哈希按照username/gisthash的格式填写到回答即可。
engine.OnRequest().SetBlock(false).FirstPriority().Handle(func(ctx *zero.Ctx) { engine.OnRequest().SetBlock(false).FirstPriority().Handle(func(ctx *zero.Ctx) {
if ctx.Event.RequestType == "friend" { /*if ctx.Event.RequestType == "friend" {
ctx.SetFriendAddRequest(ctx.Event.Flag, true, "") ctx.SetFriendAddRequest(ctx.Event.Flag, true, "")
}*/
c, ok := control.Lookup("manager")
if ok && c.GetData(ctx.Event.GroupID)&0x10 == 0x10 && ctx.Event.RequestType == "group" && ctx.Event.SubType == "add" {
// gist 文件名是群号的 ascii 编码的 md5
// gist 内容是当前 uinx 时间戳,在 10 分钟内视为有效
ans := ctx.Event.Comment[strings.Index(ctx.Event.Comment, "答案:")+len("答案:"):]
divi := strings.Index(ans, "/")
ghun := ans[:divi]
hash := ans[divi+1:]
logrus.Infoln("[manager]收到加群申请, 用户:", ghun, ", hash:", hash)
ok, reason := checkNewUser(ctx.Event.UserID, ctx.Event.GroupID, ghun, hash)
if ok {
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", true, "")
} else {
ctx.SetGroupAddRequest(ctx.Event.Flag, "add", false, reason)
} }
if ctx.Event.RequestType == "group" && ctx.Event.SubType == "invite" {
ctx.SetGroupAddRequest(ctx.Event.Flag, "invite", true, "我爱你mua~")
} }
}) })
*/
} }
func strToInt(str string) int64 { func strToInt(str string) int64 {
val, _ := strconv.ParseInt(str, 10, 64) val, _ := strconv.ParseInt(str, 10, 64)
return val return val
} }
// loadConfig 加载设置,没有则手动初始化
func loadConfig() {
mkdirerr := os.MkdirAll(datapath, 0755)
if mkdirerr == nil {
if file.IsExist(confile) {
f, err := os.Open(confile)
if err == nil {
data, err1 := io.ReadAll(f)
if err1 == nil {
if len(data) > 0 {
if proto.Unmarshal(data, &config) == nil {
return
}
}
}
}
}
config.Checkin = make(map[int64]bool)
config.Welcome = make(map[int64]string)
} else {
panic(mkdirerr)
}
}
// saveConfig 保存设置,无此文件则新建
func saveConfig() error {
data, err := proto.Marshal(&config)
if err != nil {
return err
} else if file.IsExist(datapath) {
f, err1 := os.OpenFile(confile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err1 != nil {
return err1
}
defer f.Close()
_, err2 := f.Write(data)
return err2
}
return nil
}

View File

@ -1,6 +0,0 @@
package manager
type Config struct {
Checkin map[int64]bool `protobuf:"bytes,1,rep" protobuf_key:"varint,1,opt" protobuf_val:"varint,2,opt"`
Welcome map[int64]string `protobuf:"bytes,2,rep" protobuf_key:"varint,1,opt" protobuf_val:"bytes,2,opt"`
}

View File

@ -37,8 +37,8 @@ var (
} }
) )
func NewClock(dbfile string) (c Clock) { func NewClock(db *sql.Sqlite) (c Clock) {
c.loadTimers(dbfile) c.loadTimers(db)
c.cron = cron.New() c.cron = cron.New()
c.entries = make(map[uint32]cron.EntryID) c.entries = make(map[uint32]cron.EntryID)
c.cron.Start() c.cron.Start()
@ -167,9 +167,9 @@ func (c *Clock) AddTimer(t *Timer) (err error) {
return return
} }
func (c *Clock) loadTimers(dbfile string) { func (c *Clock) loadTimers(db *sql.Sqlite) {
if file.IsExist(dbfile) { if file.IsExist(db.DBPath) {
c.db.DBPath = dbfile c.db = db
err := c.db.Create("timer", &Timer{}) err := c.db.Create("timer", &Timer{})
if err == nil { if err == nil {
var t Timer var t Timer

View File

@ -16,3 +16,11 @@ func Min(a, b int) int {
} }
return a return a
} }
// Abs 返回绝对值,该函数将被内联
func Abs(x int) int {
if x < 0 {
return -x
}
return x
}

View File

@ -1,6 +1,7 @@
package web package web
import ( import (
"errors"
"io" "io"
"net/http" "net/http"
) )
@ -23,3 +24,18 @@ func ReqWith(url string, method string, referer string, ua string) (data []byte,
} }
return return
} }
func GetData(url string) (data []byte, err error) {
var response *http.Response
response, err = http.Get(url)
if err == nil {
if response.ContentLength <= 0 {
err = errors.New("web.GetData: empty body")
response.Body.Close()
return
}
data, err = io.ReadAll(response.Body)
response.Body.Close()
}
return
}