feat: SafeLine CE 9.3.9 with pro features
MCP Docker / build-and-push (push) Has been cancelled

- Remove telemetry: disabled all phone-home (installation notify, false positives, behavior tracking, upgrade tips)
- Version branding: removed 'ce-' prefix, product name changed to '长亭雷池 WAF'
- Detection engine enhancement: strict preset enables all 17 modules with aggressive configs
- Multi-user RBAC: admin/operator/viewer roles with password + TOTP 2FA
- Rate limiting: nginx limit_req per website (RPS, burst, action)
- JS Challenge: browser fingerprint verification page with cookie-based bypass
- Security fixes: removed InsecureSkipVerify, hardcoded credentials, NO_AUTH backdoor
This commit is contained in:
2026-07-04 07:59:04 +08:00
commit b8788c239e
259 changed files with 23055 additions and 0 deletions
@@ -0,0 +1,45 @@
package analyze
import (
"context"
"github.com/chaitin/SafeLine/mcp_server/internal/api/analyze"
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
)
type GetAttackEventsParams struct {
IP string `json:"ip" desc:"ip" required:"false"`
Page int `json:"page" desc:"page" required:"false" default:"1"`
PageSize int `json:"page_size" desc:"page size" required:"false" default:"10"`
Start int64 `json:"start" desc:"start unix timestamp in milliseconds" required:"false"`
End int64 `json:"end" desc:"end unix timestamp in milliseconds" required:"false"`
}
type GetAttackEvents struct{}
func (t *GetAttackEvents) Name() string {
return "get_attack_events"
}
func (t *GetAttackEvents) Description() string {
return "get attack events"
}
func (t *GetAttackEvents) Validate(params GetAttackEventsParams) error {
return nil
}
func (t *GetAttackEvents) Execute(ctx context.Context, params GetAttackEventsParams) (analyze.GetEventListResponse, error) {
resp, err := analyze.GetEventList(ctx, &analyze.GetEventListRequest{
IP: params.IP,
PageSize: params.PageSize,
Page: params.Page,
Start: params.Start,
End: params.End,
})
if err != nil {
return analyze.GetEventListResponse{}, err
}
logger.With("total", resp.Total).Info("get attack events")
return *resp, nil
}
@@ -0,0 +1,41 @@
package app
import (
"context"
"github.com/chaitin/SafeLine/mcp_server/internal/api/app"
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
)
type CreateApp struct{}
type CreateAppParams struct {
ServerNames []string `json:"server_names" desc:"domain list" required:"true"`
Ports []string `json:"ports" desc:"port list" required:"true"`
Upstreams []string `json:"upstreams" desc:"upstream list" required:"true"`
}
func (t *CreateApp) Name() string {
return "create_http_application"
}
func (t *CreateApp) Description() string {
return "create a new website or app"
}
func (t *CreateApp) Validate(params CreateAppParams) error {
return nil
}
func (t *CreateApp) Execute(ctx context.Context, params CreateAppParams) (int64, error) {
id, err := app.CreateApp(ctx, &app.CreateAppRequest{
ServerNames: params.ServerNames,
Ports: params.Ports,
Upstreams: params.Upstreams,
})
if err != nil {
return 0, err
}
logger.Info("create app success", logger.Int64("id", id))
return id, nil
}
+46
View File
@@ -0,0 +1,46 @@
package tools
import (
"context"
"github.com/chaitin/SafeLine/mcp_server/pkg/errors"
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
)
type CalculateSum struct{}
func (t *CalculateSum) Name() string {
return "calculate_sum"
}
func (t *CalculateSum) Description() string {
return "Add two numbers together"
}
type MyToolInput struct {
A int `json:"a" desc:"number a" required:"true"`
B int `json:"b" desc:"number b" required:"true"`
}
type MyToolOutput struct {
C int `json:"c"`
}
func (t *CalculateSum) Validate(params MyToolInput) error {
return nil
}
func (t *CalculateSum) Execute(ctx context.Context, params MyToolInput) (MyToolOutput, error) {
logger.With("a", params.A).
With("b", params.B).
Debug("Executing calculation")
result := MyToolOutput{
C: params.A + params.B,
}
logger.With("result", result.C).
Debug("Calculation completed")
return result, errors.New("test error")
}
+19
View File
@@ -0,0 +1,19 @@
package tools
import (
"github.com/chaitin/SafeLine/mcp_server/internal/tools/analyze"
"github.com/chaitin/SafeLine/mcp_server/internal/tools/app"
"github.com/chaitin/SafeLine/mcp_server/internal/tools/rule"
)
func init() {
// app
AppendTool(&app.CreateApp{})
// rule
AppendTool(&rule.CreateBlacklistRule{})
AppendTool(&rule.CreateWhitelistRule{})
// analyze
AppendTool(&analyze.GetAttackEvents{})
}
@@ -0,0 +1,66 @@
package rule
import (
"context"
"github.com/chaitin/SafeLine/mcp_server/internal/api"
"github.com/chaitin/SafeLine/mcp_server/internal/api/rule"
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
)
type CreateBlacklistRule struct{}
type CreateBlacklistRuleParams struct {
Name string `json:"name" desc:"name" required:"true"`
IP []string `json:"ip" desc:"ip" required:"false"`
URINoQuery []string `json:"uri_no_query" desc:"uri_no_query" required:"false"`
}
func (t *CreateBlacklistRule) Name() string {
return "create_blacklist_rule"
}
func (t *CreateBlacklistRule) Description() string {
return "create a new blacklist rule"
}
func (t *CreateBlacklistRule) Validate(params CreateBlacklistRuleParams) error {
return nil
}
func (t *CreateBlacklistRule) Execute(ctx context.Context, params CreateBlacklistRuleParams) (int64, error) {
var pattern [][]api.Pattern
if len(params.IP) > 0 {
pattern = append(pattern, []api.Pattern{
{
K: api.KeySrcIP,
Op: api.OpEq,
V: params.IP,
SubK: "",
},
})
}
if len(params.URINoQuery) > 0 {
pattern = append(pattern, []api.Pattern{
{
K: api.KeyURINoQuery,
Op: api.OpEq,
V: params.URINoQuery,
SubK: "",
},
})
}
id, err := rule.CreateRule(ctx, &rule.CreateRuleRequest{
Name: params.Name,
IP: params.IP,
IsEnabled: true,
Action: int(api.PolicyRuleActionDeny),
Pattern: pattern,
})
if err != nil {
return 0, err
}
logger.With("id", id).Info("create blacklist rule success")
return id, nil
}
@@ -0,0 +1,66 @@
package rule
import (
"context"
"github.com/chaitin/SafeLine/mcp_server/internal/api"
"github.com/chaitin/SafeLine/mcp_server/internal/api/rule"
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
)
type CreateWhitelistRule struct{}
type CreateWhitelistRuleParams struct {
Name string `json:"name" desc:"name" required:"true"`
IP []string `json:"ip" desc:"ip" required:"false"`
URINoQuery []string `json:"uri_no_query" desc:"uri_no_query" required:"false"`
}
func (t *CreateWhitelistRule) Name() string {
return "create_whitelist_rule"
}
func (t *CreateWhitelistRule) Description() string {
return "create a new whitelist rule"
}
func (t *CreateWhitelistRule) Validate(params CreateWhitelistRuleParams) error {
return nil
}
func (t *CreateWhitelistRule) Execute(ctx context.Context, params CreateWhitelistRuleParams) (int64, error) {
var pattern [][]api.Pattern
if len(params.IP) > 0 {
pattern = append(pattern, []api.Pattern{
{
K: api.KeySrcIP,
Op: api.OpEq,
V: params.IP,
SubK: "",
},
})
}
if len(params.URINoQuery) > 0 {
pattern = append(pattern, []api.Pattern{
{
K: api.KeyURINoQuery,
Op: api.OpEq,
V: params.URINoQuery,
SubK: "",
},
})
}
id, err := rule.CreateRule(ctx, &rule.CreateRuleRequest{
Name: params.Name,
IP: params.IP,
IsEnabled: true,
Action: int(api.PolicyRuleActionAllow),
Pattern: pattern,
})
if err != nil {
return 0, err
}
logger.With("id", id).Info("create whitelist rule success")
return id, nil
}
+41
View File
@@ -0,0 +1,41 @@
package tools
import (
"github.com/chaitin/SafeLine/mcp_server/pkg/logger"
"github.com/chaitin/SafeLine/mcp_server/pkg/mcp"
)
// By deferring the concretization of generic types to the Register method,
// we avoid type inference issues.
// Each Tool is wrapped in a toolWrapper that knows its concrete type,
// allowing correct passing of generic parameters during registration.
type ToolWrapper interface {
Register(s *mcp.MCPServer) error
}
var (
tools = []ToolWrapper{}
)
func AppendTool[T any, R any](tool ...mcp.Tool[T, R]) {
for _, t := range tool {
tools = append(tools, &toolWrapper[T, R]{tool: t})
}
}
func Tools() []ToolWrapper {
return tools
}
type toolWrapper[T any, R any] struct {
tool mcp.Tool[T, R]
}
func (w *toolWrapper[T, R]) Register(s *mcp.MCPServer) error {
logger.Info("Registering tool",
logger.String("name", w.tool.Name()),
logger.String("description", w.tool.Description()),
)
return mcp.RegisterTool(s, w.tool)
}