mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-13 09:25:14 +03:00
c5e1e54c75
xray-core opens an XDRIVE stream's storage only when the inbound starts listening, so a Google Drive inbound saved with the form's defaults (no folder, no secrets), a local one without a folder, or a template one whose template xray cannot use stopped xray and every other inbound with it. validateXDriveStorage applies the core's storage rules at save, on inbound add/update and on the xray template's inbounds and outbounds: the service must be local, Google Drive or template; local and Google Drive need a remoteFolder; Google Drive needs its three non-empty secrets; a template must pass newTemplateStorage's checks (put, get, list and delete urls, and a list namesRegex with one capture group). A VLESS client kept its xtls-rprx-vision flow when its inbound moved to a transport that cannot carry it, and GetXrayConfig only honoured DisableFlow, so the server demanded Vision there and refused every client. GetXrayConfig and the outbound form now apply the Vision gate, and that gate now follows the core in the backend, the subscription service and the frontend: TLS/REALITY on raw TCP, or VLESS encryption on any transport (xray runs Vision inside encryption.CommonConn whatever the transport, not only on XHTTP). The outbound modal passes the VLESS encryption into the gate and gates Mux on the effective flow.
92 lines
4.7 KiB
Go
92 lines
4.7 KiB
Go
package service
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
func xdriveInbound(port int, xdriveSettings string) *model.Inbound {
|
|
return &model.Inbound{
|
|
Enable: true, Listen: "127.0.0.1", Port: port, Protocol: model.VLESS,
|
|
Settings: `{"clients":[],"decryption":"none"}`,
|
|
StreamSettings: `{"network":"xdrive","security":"none","xdriveSettings":` + xdriveSettings + `}`,
|
|
}
|
|
}
|
|
|
|
// xray-core opens XDRIVE storage when the listener starts; a storage it refuses there stops every inbound.
|
|
func TestAddInboundRefusesXDriveStorageTheCoreCannotOpen(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
settings string
|
|
want string
|
|
}{
|
|
{"local without folder", `{"service":"local","remoteFolder":""}`, `XDRIVE needs a "remoteFolder"`},
|
|
{"google drive without folder", `{"service":"Google Drive","remoteFolder":" ","secrets":["id","secret","token"]}`, `XDRIVE needs a "remoteFolder"`},
|
|
{"google drive with two secrets", `{"service":"Google Drive","remoteFolder":"f","secrets":["id","secret"]}`, "Google Drive needs 3 secrets"},
|
|
{"google drive with an empty secret", `{"service":"Google Drive","remoteFolder":"f","secrets":["id","","token"]}`, "Google Drive needs 3 secrets"},
|
|
{"template without template", `{"service":"template","remoteFolder":"f"}`, `XDRIVE service "template" needs a "template" object`},
|
|
{"template that is empty", `{"service":"template","remoteFolder":"f","template":{}}`, "XDRIVE template needs put, get, list and delete operations"},
|
|
{"template that is not an object", `{"service":"template","remoteFolder":"f","template":"put"}`, "XDRIVE template is not a valid storage template"},
|
|
{"template without a delete op", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"(.+)"}}}`, "XDRIVE template needs put, get, list and delete operations"},
|
|
{"template without namesRegex", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u"},"delete":{"url":"u"}}}`, "XDRIVE template list needs a namesRegex"},
|
|
{"template namesRegex without a group", `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"name"},"delete":{"url":"u"}}}`, "XDRIVE template namesRegex needs one capture group"},
|
|
{"unknown service", `{"service":"Dropbox","remoteFolder":"f"}`, `unsupported XDRIVE service "Dropbox"`},
|
|
}
|
|
for i, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
setupBulkDB(t)
|
|
_, _, err := (&InboundService{}).AddInbound(xdriveInbound(18460+i, tc.settings))
|
|
if err == nil || !strings.Contains(err.Error(), tc.want) {
|
|
t.Fatalf("AddInbound err = %v, want one containing %q", err, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAddInboundAcceptsACompleteXDriveTemplate(t *testing.T) {
|
|
setupBulkDB(t)
|
|
tmpl := `{"service":"template","template":{"put":{"url":"u"},"get":{"url":"u"},"list":{"url":"u","namesRegex":"\"name\":\"([^\"]+)\""},"delete":{"url":"u"}}}`
|
|
if _, _, err := (&InboundService{}).AddInbound(xdriveInbound(18480, tmpl)); err != nil {
|
|
t.Fatalf("AddInbound of a template xray-core can open: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSavePathsRefuseXDriveWithoutStorage(t *testing.T) {
|
|
const want = `XDRIVE needs a "remoteFolder"`
|
|
const empty = `{"service":"local","remoteFolder":""}`
|
|
tests := []struct {
|
|
name string
|
|
save func(t *testing.T) error
|
|
}{
|
|
{"update inbound", func(t *testing.T) error {
|
|
in, _, err := (&InboundService{}).AddInbound(xdriveInbound(18470, `{"service":"local","remoteFolder":"/tmp/drive"}`))
|
|
if err != nil {
|
|
t.Fatalf("AddInbound of a complete XDRIVE inbound: %v", err)
|
|
}
|
|
in.StreamSettings = xdriveInbound(18470, empty).StreamSettings
|
|
_, _, err = (&InboundService{}).UpdateInbound(in)
|
|
return err
|
|
}},
|
|
{"xray template inbound", func(t *testing.T) error {
|
|
return (&XraySettingService{}).SaveXraySetting(`{"inbounds":[{"tag":"drive","port":18471,"protocol":"vless",
|
|
"settings":{"clients":[],"decryption":"none"},"streamSettings":` + xdriveInbound(18471, empty).StreamSettings + `}],
|
|
"outbounds":[{"protocol":"freedom","tag":"direct"}]}`)
|
|
}},
|
|
{"xray template outbound", func(t *testing.T) error {
|
|
return (&XraySettingService{}).SaveXraySetting(`{"outbounds":[{"protocol":"freedom","tag":"direct"},
|
|
{"protocol":"vless","tag":"drive-out","settings":{"address":"drive.example","port":443,"id":"11111111-2222-4333-8444-555555555555","encryption":"none"},
|
|
"streamSettings":` + xdriveInbound(0, empty).StreamSettings + `}]}`)
|
|
}},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
setupBulkDB(t)
|
|
if err := tc.save(t); err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Fatalf("save err = %v, want one containing %q", err, want)
|
|
}
|
|
})
|
|
}
|
|
}
|