mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-16 16:10:21 +02:00
Add files via upload
This commit is contained in:
+73
-14
@@ -455,15 +455,15 @@ type MultiAgentAPIUpdate struct {
|
|||||||
|
|
||||||
// RobotsConfig 机器人配置(企业微信、钉钉、飞书、微信 iLink、Telegram、Slack、Discord、QQ 等)
|
// RobotsConfig 机器人配置(企业微信、钉钉、飞书、微信 iLink、Telegram、Slack、Discord、QQ 等)
|
||||||
type RobotsConfig struct {
|
type RobotsConfig struct {
|
||||||
Session RobotSessionConfig `yaml:"session,omitempty" json:"session,omitempty"` // 机器人会话隔离策略
|
Session RobotSessionConfig `yaml:"session,omitempty" json:"session,omitempty"` // 机器人会话隔离策略
|
||||||
Wechat RobotWechatConfig `yaml:"wechat,omitempty" json:"wechat,omitempty"` // 微信(iLink 扫码绑定)
|
Wechat RobotWechatConfig `yaml:"wechat,omitempty" json:"wechat,omitempty"` // 微信(iLink 扫码绑定)
|
||||||
Wecom RobotWecomConfig `yaml:"wecom,omitempty" json:"wecom,omitempty"` // 企业微信
|
Wecom RobotWecomConfig `yaml:"wecom,omitempty" json:"wecom,omitempty"` // 企业微信
|
||||||
Dingtalk RobotDingtalkConfig `yaml:"dingtalk,omitempty" json:"dingtalk,omitempty"` // 钉钉
|
Dingtalk RobotDingtalkConfig `yaml:"dingtalk,omitempty" json:"dingtalk,omitempty"` // 钉钉
|
||||||
Lark RobotLarkConfig `yaml:"lark,omitempty" json:"lark,omitempty"` // 飞书
|
Lark RobotLarkConfig `yaml:"lark,omitempty" json:"lark,omitempty"` // 飞书
|
||||||
Telegram RobotTelegramConfig `yaml:"telegram,omitempty" json:"telegram,omitempty"` // Telegram
|
Telegram RobotTelegramConfig `yaml:"telegram,omitempty" json:"telegram,omitempty"` // Telegram
|
||||||
Slack RobotSlackConfig `yaml:"slack,omitempty" json:"slack,omitempty"` // Slack
|
Slack RobotSlackConfig `yaml:"slack,omitempty" json:"slack,omitempty"` // Slack
|
||||||
Discord RobotDiscordConfig `yaml:"discord,omitempty" json:"discord,omitempty"` // Discord
|
Discord RobotDiscordConfig `yaml:"discord,omitempty" json:"discord,omitempty"` // Discord
|
||||||
QQ RobotQQConfig `yaml:"qq,omitempty" json:"qq,omitempty"` // QQ 机器人
|
QQ RobotQQConfig `yaml:"qq,omitempty" json:"qq,omitempty"` // QQ 机器人
|
||||||
}
|
}
|
||||||
|
|
||||||
// RobotWechatConfig 微信 iLink 机器人配置(个人微信 ClawBot / iLink 协议)
|
// RobotWechatConfig 微信 iLink 机器人配置(个人微信 ClawBot / iLink 协议)
|
||||||
@@ -540,9 +540,9 @@ type RobotTelegramConfig struct {
|
|||||||
|
|
||||||
// RobotSlackConfig Slack 机器人配置(Socket Mode,无需公网回调)
|
// RobotSlackConfig Slack 机器人配置(Socket Mode,无需公网回调)
|
||||||
type RobotSlackConfig struct {
|
type RobotSlackConfig struct {
|
||||||
Enabled bool `yaml:"enabled" json:"enabled"`
|
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||||
BotToken string `yaml:"bot_token" json:"bot_token"` // xoxb-
|
BotToken string `yaml:"bot_token" json:"bot_token"` // xoxb-
|
||||||
AppToken string `yaml:"app_token" json:"app_token"` // xapp-(connections:write)
|
AppToken string `yaml:"app_token" json:"app_token"` // xapp-(connections:write)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RobotDiscordConfig Discord 机器人配置(Gateway WebSocket)
|
// RobotDiscordConfig Discord 机器人配置(Gateway WebSocket)
|
||||||
@@ -1074,11 +1074,11 @@ func PersistAuthPassword(path, password string) error {
|
|||||||
if strings.HasPrefix(strings.TrimSpace(line), "password:") {
|
if strings.HasPrefix(strings.TrimSpace(line), "password:") {
|
||||||
prefix := line[:len(line)-len(strings.TrimLeft(line, " "))]
|
prefix := line[:len(line)-len(strings.TrimLeft(line, " "))]
|
||||||
comment := ""
|
comment := ""
|
||||||
if idx := strings.Index(line, "#"); idx >= 0 {
|
if idx := yamlLineCommentIndex(line); idx >= 0 {
|
||||||
comment = strings.TrimRight(line[idx:], " ")
|
comment = strings.TrimRight(line[idx:], " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
newLine := fmt.Sprintf("%spassword: %s", prefix, password)
|
newLine := fmt.Sprintf("%spassword: %s", prefix, quoteYAMLString(password))
|
||||||
if comment != "" {
|
if comment != "" {
|
||||||
if !strings.HasPrefix(comment, " ") {
|
if !strings.HasPrefix(comment, " ") {
|
||||||
newLine += " "
|
newLine += " "
|
||||||
@@ -1093,6 +1093,65 @@ func PersistAuthPassword(path, password string) error {
|
|||||||
return os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0644)
|
return os.WriteFile(path, []byte(strings.Join(lines, "\n")), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quoteYAMLString(value string) string {
|
||||||
|
node := yaml.Node{
|
||||||
|
Kind: yaml.ScalarNode,
|
||||||
|
Tag: "!!str",
|
||||||
|
Style: yaml.DoubleQuotedStyle,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
data, err := yaml.Marshal(&node)
|
||||||
|
if err != nil {
|
||||||
|
return strconv.Quote(value)
|
||||||
|
}
|
||||||
|
return strings.TrimSuffix(string(data), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func yamlLineCommentIndex(line string) int {
|
||||||
|
inSingleQuote := false
|
||||||
|
inDoubleQuote := false
|
||||||
|
escaped := false
|
||||||
|
|
||||||
|
for i, r := range line {
|
||||||
|
if inDoubleQuote {
|
||||||
|
if escaped {
|
||||||
|
escaped = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == '\\' {
|
||||||
|
escaped = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == '"' {
|
||||||
|
inDoubleQuote = false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if inSingleQuote {
|
||||||
|
if r == '\'' {
|
||||||
|
inSingleQuote = false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case '"':
|
||||||
|
inDoubleQuote = true
|
||||||
|
case '\'':
|
||||||
|
inSingleQuote = true
|
||||||
|
case '#':
|
||||||
|
if i == 0 || isYAMLWhitespace(line[i-1]) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func isYAMLWhitespace(b byte) bool {
|
||||||
|
return b == ' ' || b == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
func PrintGeneratedPasswordWarning(password string, persisted bool, persistErr string) {
|
func PrintGeneratedPasswordWarning(password string, persisted bool, persistErr string) {
|
||||||
if strings.TrimSpace(password) == "" {
|
if strings.TrimSpace(password) == "" {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPersistAuthPasswordQuotesYAMLSpecialCharacters(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "config.yaml")
|
||||||
|
initial := strings.Join([]string{
|
||||||
|
"server:",
|
||||||
|
" host: 0.0.0.0",
|
||||||
|
"auth:",
|
||||||
|
" password: old-password # Web 登录密码",
|
||||||
|
" session_duration_hours: 12",
|
||||||
|
"log:",
|
||||||
|
" level: info",
|
||||||
|
"",
|
||||||
|
}, "\n")
|
||||||
|
if err := os.WriteFile(path, []byte(initial), 0644); err != nil {
|
||||||
|
t.Fatalf("write config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := `@abc:def # still password`
|
||||||
|
if err := PersistAuthPassword(path, want); err != nil {
|
||||||
|
t.Fatalf("PersistAuthPassword: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read config: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(data), `password: "@abc:def # still password" # Web 登录密码`) {
|
||||||
|
t.Fatalf("password was not safely quoted or comment was not preserved:\n%s", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := Load(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Load after PersistAuthPassword: %v", err)
|
||||||
|
}
|
||||||
|
if cfg.Auth.Password != want {
|
||||||
|
t.Fatalf("Auth.Password = %q, want %q", cfg.Auth.Password, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPersistAuthPasswordDoesNotTreatQuotedHashAsComment(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "config.yaml")
|
||||||
|
initial := strings.Join([]string{
|
||||||
|
"auth:",
|
||||||
|
` password: "old#password"`,
|
||||||
|
" session_duration_hours: 12",
|
||||||
|
"",
|
||||||
|
}, "\n")
|
||||||
|
if err := os.WriteFile(path, []byte(initial), 0644); err != nil {
|
||||||
|
t.Fatalf("write config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := PersistAuthPassword(path, "new-password"); err != nil {
|
||||||
|
t.Fatalf("PersistAuthPassword: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read config: %v", err)
|
||||||
|
}
|
||||||
|
if strings.Contains(string(data), "#password") {
|
||||||
|
t.Fatalf("old quoted password fragment was incorrectly preserved as a comment:\n%s", data)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user