Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8af2d7e
Update
Mtoly Dec 23, 2025
ad261e7
update
Mtoly Jan 8, 2026
079fb34
build(deps): bump github.com/redis/go-redis/v9 from 9.7.3 to 9.17.2
dependabot[bot] Jan 10, 2026
0c12721
build(deps): bump golang.org/x/time from 0.12.0 to 0.14.0
dependabot[bot] Jan 10, 2026
2d4ab15
build(deps): bump github.com/eko/gocache/store/go_cache/v4
dependabot[bot] Jan 10, 2026
4a70f89
build(deps): bump github.com/spf13/cobra from 1.9.1 to 1.10.2
dependabot[bot] Jan 10, 2026
c33442d
Merge pull request #1 from Mtoly/dependabot/go_modules/github.com/red…
Mtoly Jan 10, 2026
27a175d
Merge pull request #2 from Mtoly/dependabot/go_modules/golang.org/x/t…
Mtoly Jan 10, 2026
f11c61b
Merge pull request #3 from Mtoly/dependabot/go_modules/github.com/eko…
Mtoly Jan 10, 2026
27a1a54
Merge pull request #4 from Mtoly/dependabot/go_modules/github.com/spf…
Mtoly Jan 10, 2026
f628091
build(deps): bump github.com/fsnotify/fsnotify from 1.7.0 to 1.9.0
dependabot[bot] Jan 10, 2026
5dea9d4
Merge pull request #5 from Mtoly/dependabot/go_modules/github.com/fsn…
Mtoly Jan 10, 2026
2e9ffc0
update
Mtoly Jan 12, 2026
d20af33
build(deps): bump github.com/eko/gocache/store/go_cache/v4
dependabot[bot] Jan 13, 2026
79194ab
update
Mtoly Jan 13, 2026
e4bcdbd
update
Mtoly Jan 15, 2026
ca79907
build(deps): bump github.com/go-resty/resty/v2 from 2.13.1 to 2.17.1
dependabot[bot] Jan 15, 2026
3243fdc
Merge pull request #11 from Mtoly/dependabot/go_modules/github.com/ek…
Mtoly Jan 15, 2026
ae199a7
Merge pull request #8 from Mtoly/dependabot/go_modules/github.com/go-…
Mtoly Jan 15, 2026
06da204
update
Mtoly Jan 16, 2026
863a2d2
update
Mtoly Jan 28, 2026
0ce3be7
build(deps): bump github.com/sagernet/sing-box from 1.12.17 to 1.12.18
dependabot[bot] Jan 30, 2026
5f64490
Merge pull request #20 from Mtoly/dependabot/go_modules/github.com/sa…
Mtoly Feb 2, 2026
bb71b4b
update
Mtoly Mar 12, 2026
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
10 changes: 5 additions & 5 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -48,13 +48,13 @@ jobs:
# queries: ./path/to/local/query, your-org/your-repo/queries@main

- name: Install Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: go.mod
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -68,4 +68,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
2 changes: 1 addition & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
- published
env:
REGISTRY: ghcr.io
IMAGE_NAME: xrayr-project/xrayr
IMAGE_NAME: XrayR-project/XrayR

jobs:
build:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ jobs:
CGO_ENABLED: 0
steps:
- name: Checkout codebase
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Show workflow information
id: get_filename
run: |
Expand All @@ -109,9 +109,9 @@ jobs:
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV

- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ^1.20
go-version-file: go.mod

- name: Get project dependencies
run: go mod download
Expand All @@ -133,7 +133,7 @@ jobs:
mv XrayR XrayR.exe

- name: Prepare to release
uses: nick-fields/retry@v2
uses: nick-fields/retry@v3
with:
timeout_minutes: 60
retry_wait_seconds: 60
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
- uses: actions/stale@v9
with:
days-before-issue-stale: 30
days-before-issue-close: 14
Expand Down
2 changes: 2 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package api
// API is the interface for different panel's api.
type API interface {
GetNodeInfo() (nodeInfo *NodeInfo, err error)
// GetXrayRCertConfig returns optional global certificate settings from panel
GetXrayRCertConfig() (certConfig *XrayRCertConfig, err error)
GetUserList() (userList *[]UserInfo, err error)
ReportNodeStatus(nodeStatus *NodeStatus) (err error)
ReportNodeOnlineUsers(onlineUser *[]OnlineUser) (err error)
Expand Down
69 changes: 68 additions & 1 deletion api/apimodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ type NodeStatus struct {
type NodeInfo struct {
AcceptProxyProtocol bool
Authority string
NodeType string // Must be V2ray, Trojan, and Shadowsocks
NodeType string // V2ray/Vmess, VLESS, Trojan, Shadowsocks, Hysteria2, AnyTLS, Tuic, Socks, HTTP
NodeID int
Port uint32
SpeedLimit uint64 // Bps
AlterID uint16
TransportProtocol string
FakeType string
Host string
SNI string
Path string
EnableTLS bool
EnableSniffing bool
Expand Down Expand Up @@ -78,6 +79,40 @@ type NodeInfo struct {
Security string
Key string
RejectUnknownSni bool
Hysteria2Config *Hysteria2Config
AnyTLSConfig *AnyTLSConfig
TuicConfig *TuicConfig

// XHTTP (SplitHTTP) bypass CDN fields — new in Xray-core v26.2+
XHTTPMode string // auto, packet-up, stream-up, stream-one
XHTTPExtra json.RawMessage // raw "extra" JSON for full override
XPaddingBytes *[2]int32 // [from, to] range for xPaddingBytes
XPaddingObfsMode bool // xPaddingObfsMode
XPaddingKey string // xPaddingKey
XPaddingHeader string // xPaddingHeader
XPaddingPlacement string // queryInHeader, cookie, header, query
XPaddingMethod string // repeat-x, tokenish
UplinkHTTPMethod string // POST, GET
SessionPlacement string // path, cookie, header, query
SessionKey string // key for session placement
SeqPlacement string // path, cookie, header, query
SeqKey string // key for seq placement
UplinkDataPlacement string // body, cookie, header
UplinkDataKey string // key for uplink data placement
UplinkChunkSize uint32 // chunk size for non-body uplink
NoGRPCHeader bool // disable gRPC header
NoSSEHeader bool // disable SSE header
ScMaxEachPostBytes *[2]int32 // [from, to] range
ScMinPostsIntervalMs *[2]int32 // [from, to] range
ScMaxBufferedPosts int64 // max buffered posts
ScStreamUpServerSecs *[2]int32 // [from, to] range
XmuxMaxConcurrency *[2]int32 // [from, to] range
XmuxMaxConnections *[2]int32 // [from, to] range
XmuxCMaxReuseTimes *[2]int32 // [from, to] range
XmuxHMaxRequestTimes *[2]int32 // [from, to] range
XmuxHMaxReusableSecs *[2]int32 // [from, to] range
XmuxHKeepAlivePeriod int64 // keep alive period
XHTTPDownloadSettings json.RawMessage // downloadSettings raw JSON
}

type UserInfo struct {
Expand Down Expand Up @@ -119,6 +154,38 @@ type DetectRule struct {
type DetectResult struct {
UID int
RuleID int
IP string
}

// XrayRCertConfig carries optional panel-provided certificate settings
// (e.g., DNS provider, ACME email, and DNS-01 environment variables).
type XrayRCertConfig struct {
Provider string `json:"provider"`
Email string `json:"email"`
DNSEnv map[string]string `json:"dns_env"`
}

type Hysteria2Config struct {
Obfs string
ObfsPassword string
UpMbps int
DownMbps int
IgnoreClientBandwidth bool
PortHopEnabled bool
PortHopPorts string
}

type AnyTLSConfig struct {
PaddingScheme []string
}

type TuicConfig struct {
CongestionControl string
UDPRelayMode string
ZeroRTTHandshake bool
Heartbeat int
AuthTimeout int
ALPN []string
}

type REALITYConfig struct {
Expand Down
89 changes: 77 additions & 12 deletions api/bunpanel/bunpanel.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func (*APIClient) ReportNodeStatus(nodeStatus *api.NodeStatus) (err error) {
return nil
}

// GetXrayRCertConfig is not supported by BunPanel; return nil to indicate absence.
func (*APIClient) GetXrayRCertConfig() (*api.XrayRCertConfig, error) {
return nil, nil
}

// GetNodeRule implements api.API.
func (c *APIClient) GetNodeRule() (*[]api.DetectRule, error) {
ruleList := c.LocalRuleList
Expand Down Expand Up @@ -110,9 +115,14 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {

// read line by line
for fileScanner.Scan() {
pattern, err := regexp.Compile(fileScanner.Text())
if err != nil {
log.Printf("Invalid rule regex: %s, skipping", err)
continue
}
LocalRuleList = append(LocalRuleList, api.DetectRule{
ID: -1,
Pattern: regexp.MustCompile(fileScanner.Text()),
Pattern: pattern,
})
}
// handle first encountered error while reading
Expand All @@ -127,7 +137,7 @@ func readLocalRuleList(path string) (LocalRuleList []api.DetectRule) {

// Describe return a description of the client
func (c *APIClient) Describe() api.ClientInfo {
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: c.Key, NodeType: c.NodeType}
return api.ClientInfo{APIHost: c.APIHost, NodeID: c.NodeID, Key: "", NodeType: c.NodeType}
}

// Debug set the client debug for client
Expand All @@ -144,7 +154,7 @@ func (c *APIClient) parseResponse(res *resty.Response, path string, err error) (
return nil, fmt.Errorf("request %s failed: %s", c.assembleURL(path), err)
}

if res.StatusCode() > 400 {
if res.StatusCode() >= 400 {
body := res.Body()
return nil, fmt.Errorf("request %s failed: %s, %v", c.assembleURL(path), string(body), err)
}
Expand Down Expand Up @@ -190,11 +200,6 @@ func (c *APIClient) GetNodeInfo() (nodeInfo *api.NodeInfo, err error) {
return nil, fmt.Errorf("parse node info failed: %s, \nError: %s, \nPlease check the doc of custom_config for help: https://xrayr-project.github.io/XrayR-doc/dui-jie-sspanel/sspanel/sspanel_custom_config", string(res), err)
}

if err != nil {
res, _ := json.Marshal(nodeInfoResponse)
return nil, fmt.Errorf("parse node info failed: %s, \nError: %s", string(res), err)
}

return nodeInfo, nil
}

Expand Down Expand Up @@ -403,6 +408,46 @@ func (c *APIClient) ParseNodeInfo(nodeInfoResponse *Server) (*api.NodeInfo, erro
json.Unmarshal(nodeConfig.TcpSettings, tcpConfig)
}

// Parse SplitHTTP/XHTTP settings
splithttpConfig := new(SplitHTTPSettings)
if nodeConfig.XHTTPSettings != nil {
json.Unmarshal(nodeConfig.XHTTPSettings, splithttpConfig)
} else if nodeConfig.SplitHTTPSettings != nil {
json.Unmarshal(nodeConfig.SplitHTTPSettings, splithttpConfig)
}

// Parse HttpUpgrade settings
httpupgradeConfig := new(HttpUpgradeSettings)
if nodeConfig.HttpUpgradeSettings != nil {
json.Unmarshal(nodeConfig.HttpUpgradeSettings, httpupgradeConfig)
}

// Determine Host and Path based on transport protocol
var host, path, serviceName string
var header json.RawMessage
var headers map[string]string

switch transportProtocol {
case "ws":
host = wsConfig.Headers.Host
path = wsConfig.Path
case "grpc":
serviceName = grpcConfig.ServiceName
case "tcp":
header = tcpConfig.Header
case "splithttp", "xhttp":
host = splithttpConfig.Host
path = splithttpConfig.Path
headers = splithttpConfig.Headers
case "httpupgrade":
host = httpupgradeConfig.Host
path = httpupgradeConfig.Path
headers = httpupgradeConfig.Headers
default:
host = wsConfig.Headers.Host
path = wsConfig.Path
}

// Create GeneralNodeInfo
nodeInfo := &api.NodeInfo{
NodeType: c.NodeType,
Expand All @@ -411,16 +456,36 @@ func (c *APIClient) ParseNodeInfo(nodeInfoResponse *Server) (*api.NodeInfo, erro
SpeedLimit: speedLimit,
AlterID: alterID,
TransportProtocol: transportProtocol,
Host: wsConfig.Headers.Host,
Path: wsConfig.Path,
Host: host,
Path: path,
EnableTLS: enableTLS,
EnableVless: enableVless,
VlessFlow: nodeConfig.Flow,
CypherMethod: nodeConfig.Method,
ServiceName: grpcConfig.ServiceName,
Header: tcpConfig.Header,
ServiceName: serviceName,
Header: header,
Headers: headers,
EnableREALITY: enableREALITY,
REALITYConfig: realityConfig,
// XHTTP bypass CDN fields
XHTTPMode: splithttpConfig.Mode,
XHTTPExtra: splithttpConfig.Extra,
XPaddingBytes: splithttpConfig.XPaddingBytes,
XPaddingObfsMode: splithttpConfig.XPaddingObfsMode,
XPaddingKey: splithttpConfig.XPaddingKey,
XPaddingHeader: splithttpConfig.XPaddingHeader,
XPaddingPlacement: splithttpConfig.XPaddingPlacement,
XPaddingMethod: splithttpConfig.XPaddingMethod,
UplinkHTTPMethod: splithttpConfig.UplinkHTTPMethod,
SessionPlacement: splithttpConfig.SessionPlacement,
SessionKey: splithttpConfig.SessionKey,
SeqPlacement: splithttpConfig.SeqPlacement,
SeqKey: splithttpConfig.SeqKey,
UplinkDataPlacement: splithttpConfig.UplinkDataPlacement,
UplinkDataKey: splithttpConfig.UplinkDataKey,
UplinkChunkSize: splithttpConfig.UplinkChunkSize,
NoGRPCHeader: splithttpConfig.NoGRPCHeader,
NoSSEHeader: splithttpConfig.NoSSEHeader,
}

return nodeInfo, nil
Expand Down
33 changes: 33 additions & 0 deletions api/bunpanel/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ type Server struct {
RealitySettings json.RawMessage `json:"realitySettings"`
GrpcSettings json.RawMessage `json:"grpcSettings"`
TcpSettings json.RawMessage `json:"tcpSettings"`
SplitHTTPSettings json.RawMessage `json:"splithttpSettings"`
XHTTPSettings json.RawMessage `json:"xhttpSettings"`
HttpUpgradeSettings json.RawMessage `json:"httpupgradeSettings"`
}

type WsSettings struct {
Expand All @@ -29,6 +32,36 @@ type TcpSettings struct {
Header json.RawMessage `json:"header"`
}

type SplitHTTPSettings struct {
Path string `json:"path"`
Host string `json:"host"`
Headers map[string]string `json:"headers"`
Mode string `json:"mode"`
Extra json.RawMessage `json:"extra"`
XPaddingBytes *[2]int32 `json:"xPaddingBytes"`
XPaddingObfsMode bool `json:"xPaddingObfsMode"`
XPaddingKey string `json:"xPaddingKey"`
XPaddingHeader string `json:"xPaddingHeader"`
XPaddingPlacement string `json:"xPaddingPlacement"`
XPaddingMethod string `json:"xPaddingMethod"`
UplinkHTTPMethod string `json:"uplinkHTTPMethod"`
SessionPlacement string `json:"sessionPlacement"`
SessionKey string `json:"sessionKey"`
SeqPlacement string `json:"seqPlacement"`
SeqKey string `json:"seqKey"`
UplinkDataPlacement string `json:"uplinkDataPlacement"`
UplinkDataKey string `json:"uplinkDataKey"`
UplinkChunkSize uint32 `json:"uplinkChunkSize"`
NoGRPCHeader bool `json:"noGRPCHeader"`
NoSSEHeader bool `json:"noSSEHeader"`
}

type HttpUpgradeSettings struct {
Path string `json:"path"`
Host string `json:"host"`
Headers map[string]string `json:"headers"`
}

type RealitySettings struct {
Show bool `json:"show"`
Dest string `json:"dest"`
Expand Down
Loading
Loading