|
|
@@ -0,0 +1,60 @@
|
|
|
+package sub
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
|
+ "github.com/mhsanaei/3x-ui/v3/internal/util/link"
|
|
|
+)
|
|
|
+
|
|
|
+// The vmess object carries the certificate checks the panel exported, so
|
|
|
+// importing that same link has to rebuild them instead of dropping them.
|
|
|
+func TestVmessTLSVerifyFieldsSurviveExportImport(t *testing.T) {
|
|
|
+ in := &model.Inbound{
|
|
|
+ Id: 940002, Listen: "203.0.113.1", Port: 8443, Protocol: model.VMESS,
|
|
|
+ Settings: `{"clients":[{"id":"11111111-2222-4333-8444-555555555555","email":"user"}]}`,
|
|
|
+ StreamSettings: `{"network":"tcp","security":"tls","tcpSettings":{"header":{"type":"none"}},` +
|
|
|
+ `"tlsSettings":{"serverName":"vmess.example.com","alpn":["h2"],"settings":{` +
|
|
|
+ `"fingerprint":"chrome","echConfigList":"AEX+DQBB","verifyPeerCertByName":"vcn.example.com",` +
|
|
|
+ `"pinnedPeerCertSha256":["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="]}}}`,
|
|
|
+ }
|
|
|
+ exported := (&SubService{}).genVmessLink(in, "user")
|
|
|
+ if exported == "" {
|
|
|
+ t.Fatal("genVmessLink produced nothing")
|
|
|
+ }
|
|
|
+
|
|
|
+ parsed, err := link.ParseLink(exported)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("ParseLink: %v", err)
|
|
|
+ }
|
|
|
+ raw, err := json.Marshal(parsed.Outbound["streamSettings"])
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("marshal stream: %v", err)
|
|
|
+ }
|
|
|
+ var stream map[string]any
|
|
|
+ if err := json.Unmarshal(raw, &stream); err != nil {
|
|
|
+ t.Fatalf("stream json: %v", err)
|
|
|
+ }
|
|
|
+ tlsSettings, _ := stream["tlsSettings"].(map[string]any)
|
|
|
+ if tlsSettings == nil {
|
|
|
+ t.Fatalf("no tlsSettings: %s", raw)
|
|
|
+ }
|
|
|
+
|
|
|
+ // The core reads these joined strings in its config, as applySecurity writes them.
|
|
|
+ for field, want := range map[string]string{
|
|
|
+ "serverName": "vmess.example.com",
|
|
|
+ "fingerprint": "chrome",
|
|
|
+ "echConfigList": "AEX+DQBB",
|
|
|
+ "verifyPeerCertByName": "vcn.example.com",
|
|
|
+ "pinnedPeerCertSha256": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
|
+ } {
|
|
|
+ if tlsSettings[field] != want {
|
|
|
+ t.Errorf("tlsSettings[%q] = %v, want %q", field, tlsSettings[field], want)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ alpn, _ := tlsSettings["alpn"].([]any)
|
|
|
+ if len(alpn) != 1 || alpn[0] != "h2" {
|
|
|
+ t.Errorf("alpn = %v, want [h2]", tlsSettings["alpn"])
|
|
|
+ }
|
|
|
+}
|