package service import ( "encoding/json" "testing" ) const completeXmcProfile = `{"username":"Notch","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}` func TestValidateFinalMaskXmcProfiles(t *testing.T) { tests := []struct { name string streamSettings string wantErr bool }{ { name: "empty streamSettings", streamSettings: "", wantErr: false, }, { name: "no finalmask", streamSettings: `{"network":"tcp","security":"none"}`, wantErr: false, }, { name: "non-xmc mask is untouched", streamSettings: `{"finalmask":{"tcp":[{"type":"fragment","settings":{"packets":"tlshello"}}]}}`, wantErr: false, }, { name: "xmc with a complete profile", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"hostname":"mc.example.com","password":"pw","profiles":[` + completeXmcProfile + `]}}]}}`, wantErr: false, }, { name: "legacy usernames shape without profiles", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"hostname":"mc.example.com","password":"pw","usernames":["Dream"]}}]}}`, wantErr: true, }, { name: "xmc with an empty profiles array", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[]}}]}}`, wantErr: true, }, { name: "profile missing the textures signature", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[{"username":"Notch","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":""}]}}]}}`, wantErr: true, }, { name: "profile with an unparseable uuid", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[{"username":"Notch","uuid":"not-a-uuid","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}]}}]}}`, wantErr: true, }, { name: "profile with an out-of-range username", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[{"username":"ab","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}]}}]}}`, wantErr: true, }, { name: "one complete and one incomplete profile", streamSettings: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[` + completeXmcProfile + `,{"username":"Herobrine","uuid":"","texturesValue":"","texturesSignature":""}]}}]}}`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validateFinalMaskXmcProfiles(tt.streamSettings) if (err != nil) != tt.wantErr { t.Errorf("validateFinalMaskXmcProfiles(%q) error = %v, wantErr %v", tt.streamSettings, err, tt.wantErr) } }) } } // TestXmcMaskProfilesCompleteExpectations pins the panel predicate's own // contract. Until the lite peel it was cross-checked against xray-core's // loader (every accepted profile had to build in the core and vice versa); // with the library gone the predicate stands on its own rules — username // ^[A-Za-z0-9_]{3,16}$, a parseable uuid, non-empty textures value and // signature, at least one profile — and this table records them. A core // release that tightens or relaxes its side is no longer detected here; // the strip/validate pair errs on the panel's documented rules instead. func TestXmcMaskProfilesCompleteExpectations(t *testing.T) { profiles := []struct { name string raw string want bool }{ {name: "complete", raw: completeXmcProfile, want: true}, {name: "undashed uuid", raw: `{"username":"Notch","uuid":"069a79f444e94726a5befca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}`, want: true}, {name: "username at the 16 char limit", raw: `{"username":"Abcdefghijklmnop","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}`, want: true}, {name: "username over the limit", raw: `{"username":"Abcdefghijklmnopq","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}`, want: false}, {name: "username with a hyphen", raw: `{"username":"No-tch","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}`, want: false}, {name: "empty uuid", raw: `{"username":"Notch","uuid":"","texturesValue":"dmFsdWU=","texturesSignature":"c2ln"}`, want: false}, {name: "missing textures value", raw: `{"username":"Notch","uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","texturesValue":"","texturesSignature":"c2ln"}`, want: false}, {name: "no profiles at all", raw: ``, want: false}, } for _, tt := range profiles { t.Run(tt.name, func(t *testing.T) { mask := map[string]any{"type": "xmc"} var settings map[string]any raw := tt.raw if raw == "" { raw = `{}` // a mask whose settings carry no profiles key at all if err := json.Unmarshal([]byte(raw), &settings); err != nil { t.Fatalf("unmarshal settings: %v", err) } } else { if err := json.Unmarshal([]byte(`{"profiles":[`+raw+`]}`), &settings); err != nil { t.Fatalf("unmarshal settings: %v", err) } } mask["settings"] = settings if got := xmcMaskProfilesComplete(mask); got != tt.want { t.Errorf("xmcMaskProfilesComplete = %v, want %v", got, tt.want) } }) } } func TestStripIncompleteXmcMasks(t *testing.T) { tests := []struct { name string stream string wantDropped int wantStream string }{ { name: "legacy usernames mask is dropped and finalmask removed", stream: `{"network":"tcp","finalmask":{"tcp":[{"type":"xmc","settings":{"usernames":["Dream"],"password":"pw"}}]}}`, wantDropped: 1, wantStream: `{"network":"tcp"}`, }, { name: "complete mask is kept", stream: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[` + completeXmcProfile + `]}}]}}`, wantDropped: 0, wantStream: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"password":"pw","profiles":[` + completeXmcProfile + `]}}]}}`, }, { name: "sibling masks survive the drop", stream: `{"finalmask":{"tcp":[{"type":"xmc","settings":{"usernames":["Dream"]}},{"type":"fragment","settings":{"packets":"tlshello"}}]}}`, wantDropped: 1, wantStream: `{"finalmask":{"tcp":[{"type":"fragment","settings":{"packets":"tlshello"}}]}}`, }, { name: "udp masks are preserved when tcp empties out", stream: `{"finalmask":{"tcp":[{"type":"xmc","settings":{}}],"udp":[{"type":"salamander"}]}}`, wantDropped: 1, wantStream: `{"finalmask":{"udp":[{"type":"salamander"}]}}`, }, { name: "stream without finalmask is untouched", stream: `{"network":"tcp","security":"tls"}`, wantDropped: 0, wantStream: `{"network":"tcp","security":"tls"}`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var stream map[string]any if err := json.Unmarshal([]byte(tt.stream), &stream); err != nil { t.Fatalf("unmarshal stream: %v", err) } dropped := stripIncompleteXmcMasks(stream) if dropped != tt.wantDropped { t.Errorf("stripIncompleteXmcMasks dropped = %d, want %d", dropped, tt.wantDropped) } var want map[string]any if err := json.Unmarshal([]byte(tt.wantStream), &want); err != nil { t.Fatalf("unmarshal wantStream: %v", err) } got, err := json.Marshal(stream) if err != nil { t.Fatalf("marshal stream: %v", err) } wantJSON, err := json.Marshal(want) if err != nil { t.Fatalf("marshal want: %v", err) } if string(got) != string(wantJSON) { t.Errorf("stream after strip = %s, want %s", got, wantJSON) } }) } }