Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,8 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 齁语解密 [密文] 或 h解密 [密文]
- [x] fumo加密 [文本]
- [x] fumo解密 [文本]
- [x] qq加密 [文本]
- [x] qq解密 [密文]

</details>
<details>
Expand Down
142 changes: 130 additions & 12 deletions plugin/crypter/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,157 @@
package crypter

import (
"fmt"
"regexp"
"strconv"
"strings"

"github.com/FloatTech/AnimeAPI/airecord"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)

var faceTagRe = regexp.MustCompile(`\{\{face:(\d+)\}\}`)

func parseID(v interface{}) int64 {
n, _ := strconv.ParseInt(fmt.Sprint(v), 10, 64)
return n
}

func serializeMsg(segs message.Message) string {
var sb strings.Builder
for _, seg := range segs {
switch seg.Type {
case "text":
sb.WriteString(seg.Data["text"])
case "face":
fmt.Fprintf(&sb, "{{face:%v}}", seg.Data["id"])
}
}
return sb.String()
}

func deserializeMsg(s string) message.Message {
var msg message.Message
parts := faceTagRe.Split(s, -1)
matches := faceTagRe.FindAllStringSubmatch(s, -1)
for i, part := range parts {
if part != "" {
msg = append(msg, message.Text(part))
}
if i < len(matches) {
id, _ := strconv.Atoi(matches[i][1])
msg = append(msg, message.Face(id))
}
}
return msg
}

func getInput(ctx *zero.Ctx, cmds ...string) string {
full := serializeMsg(ctx.Event.Message)
for _, cmd := range cmds {
if idx := strings.Index(full, cmd); idx >= 0 {
return strings.TrimSpace(full[idx+len(cmd):])
}
}
return ""
}

func getReplyContent(ctx *zero.Ctx) string {
for _, seg := range ctx.Event.Message {
if seg.Type == "reply" {
if msgID := parseID(seg.Data["id"]); msgID > 0 {
if msg := ctx.GetMessage(msgID); msg.Elements != nil {
return serializeMsg(msg.Elements)
}
}
}
}
return ""
}

func getReplyFaceIDs(ctx *zero.Ctx) []int {
for _, seg := range ctx.Event.Message {
if seg.Type == "reply" {
if msgID := parseID(seg.Data["id"]); msgID > 0 {
return extractFaceIDs(ctx.GetMessage(msgID).Elements)
}
}
}
return nil
}

func extractFaceIDs(segs message.Message) []int {
var ids []int
for _, seg := range segs {
if seg.Type == "face" {
if id := int(parseID(seg.Data["id"])); id > 0 {
ids = append(ids, id)
}
}
}
return ids
}

// hou
func houEncryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
text := getInput(ctx, "h加密", "齁语加密")
result := encodeHou(text)
recCfg := airecord.GetConfig()
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result)
if record != "" {
if record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result); record != "" {
ctx.SendChain(message.Record(record))
} else {
ctx.SendChain(message.Text(result))
}
}

func houDecryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := decodeHou(text)
ctx.SendChain(message.Text(result))
text := getInput(ctx, "h解密", "齁语解密")
if text == "" {
text = getReplyContent(ctx)
}
if text == "" {
ctx.SendChain(message.Text("请输入密文或回复加密消息"))
return
}
ctx.SendChain(deserializeMsg(decodeHou(text))...)
}

// fumo
func fumoEncryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := encryptFumo(text)
ctx.SendChain(message.Text(result))
ctx.SendChain(message.Text(encryptFumo(getInput(ctx, "fumo加密"))))
}

func fumoDecryptHandler(ctx *zero.Ctx) {
text := ctx.State["regex_matched"].([]string)[1]
result := decryptFumo(text)
ctx.SendChain(message.Text(result))
text := getInput(ctx, "fumo解密")
if text == "" {
text = getReplyContent(ctx)
}
if text == "" {
ctx.SendChain(message.Text("请输入密文或回复加密消息"))
return
}
ctx.SendChain(deserializeMsg(decryptFumo(text))...)
}

// qq表情
func qqEmojiEncryptHandler(ctx *zero.Ctx) {
text := getInput(ctx, "qq加密")
if text == "" {
ctx.SendChain(message.Text("请输入要加密的文本"))
return
}
ctx.SendChain(encodeQQEmoji(text)...)
}

func qqEmojiDecryptHandler(ctx *zero.Ctx) {
faceIDs := extractFaceIDs(ctx.Event.Message)
if len(faceIDs) == 0 {
faceIDs = getReplyFaceIDs(ctx)
}
if len(faceIDs) == 0 {
ctx.SendChain(message.Text("请回复QQ表情加密消息进行解密"))
return
}
ctx.SendChain(deserializeMsg(decodeQQEmoji(faceIDs))...)
}
20 changes: 15 additions & 5 deletions plugin/crypter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,25 @@ func init() {
"- 齁语解密 [密文] 或 h解密 [密文]\n\n" +
"- Fumo语加解密:\n" +
"- fumo加密 [文本]\n" +
"- fumo解密 [密文]\n\n",
"- fumo解密 [密文]\n\n" +
"- QQ表情加解密:\n" +
"- qq加密 [文本]\n" +
"- qq解密 [密文]\n\n" +
"注意:QQ表情解密建议使用回复,尽量不要复制粘贴\n\n",
PublicDataFolder: "Crypter",
})

re := `(?:\[CQ:reply,id=-?\d+\])?`

// hou
engine.OnRegex(`^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
engine.OnRegex(`^(?:齁语解密|h解密)\s*(.+)$`).SetBlock(true).Handle(houDecryptHandler)
engine.OnRegex(re + `^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
engine.OnRegex(re + `(?:齁语解密|h解密)\s*(.*)$`).SetBlock(true).Handle(houDecryptHandler)

// Fumo
engine.OnRegex(`^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
engine.OnRegex(`^fumo解密\s*(.+)$`).SetBlock(true).Handle(fumoDecryptHandler)
engine.OnRegex(re + `^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
engine.OnRegex(re + `fumo解密\s*(.*)$`).SetBlock(true).Handle(fumoDecryptHandler)

// QQ表情
engine.OnRegex(re + `^qq加密\s*(.+)$`).SetBlock(true).Handle(qqEmojiEncryptHandler)
engine.OnRegex(re + `qq解密`).SetBlock(true).Handle(qqEmojiDecryptHandler)
}
66 changes: 66 additions & 0 deletions plugin/crypter/qqemoji.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Package crypter QQ表情加解密
package crypter

import (
"fmt"
"strings"
"unicode/utf8"

"github.com/wdvxdr1123/ZeroBot/message"
)

const (
emojiZeroID = 297
emojiOneID = 424
)

func encodeQQEmoji(text string) message.Message {
if text == "" {
return message.Message{message.Text("请输入要加密的文本")}
}

var bin strings.Builder
for _, b := range []byte(text) {
fmt.Fprintf(&bin, "%08b", b)
}

s := bin.String()
msg := make(message.Message, 0, len(s))
for _, bit := range s {
if bit == '0' {
msg = append(msg, message.Face(emojiZeroID))
} else {
msg = append(msg, message.Face(emojiOneID))
}
}
return msg
}

func decodeQQEmoji(faceIDs []int) string {
var bin strings.Builder
for _, id := range faceIDs {
if id == emojiZeroID {
bin.WriteByte('0')
} else if id == emojiOneID {
bin.WriteByte('1')
}
}
binary := bin.String()
if len(binary) == 0 || len(binary)%8 != 0 {
return "QQ表情密文格式错误"
}

data := make([]byte, len(binary)/8)
for i := range data {
for j := 0; j < 8; j++ {
if binary[i*8+j] == '1' {
data[i] |= 1 << (7 - j)
}
}
}

if !utf8.Valid(data) {
return "QQ表情解密失败:结果不是有效文本"
}
return string(data)
}
Loading