mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-30 17:55:00 +03:00
fix(finalmask): refuse a salamander password xray-core cannot open
xray-core needs a salamander (and gecko) password of at least 4 bytes (smPSKMinLen), but checks it only when a socket opens: xray run -test reports Configuration OK. On an inbound the listener then fails and Xray does not start at all, taking every other inbound down; on a client the dial fails. The panel saved any password, and the finalmask editor starts a new salamander mask with an empty one. maskcompat.CheckSalamanderPasswords applies the core's byte rule, pinned against the core's own ListenPacket, and every path that stores a finalmask refuses a short password: inbound add and update, hosts, the subscription's global finalmask, and the inbounds and outbounds of the Xray template. The editor flags it inline as it is typed.
This commit is contained in:
@@ -995,6 +995,25 @@ func validateFinalMaskXmcProfiles(streamSettings string) error {
|
||||
return common.NewError("XMC finalmask requires at least one complete Minecraft profile — each needs a username (3-16 of A-Z a-z 0-9 _), a UUID, and both texture fields from Mojang's session server (XTLS/Xray-core#6487). Complete the profiles or remove the XMC mask.")
|
||||
}
|
||||
|
||||
// validateFinalMaskSalamander refuses at save a salamander password the core loads and then refuses
|
||||
// when the listener opens, which stops every other inbound with it.
|
||||
func validateFinalMaskSalamander(streamSettings string) error {
|
||||
var stream map[string]any
|
||||
if json.Unmarshal([]byte(streamSettings), &stream) != nil {
|
||||
return nil
|
||||
}
|
||||
return maskcompat.CheckSalamanderPasswords(stream["finalmask"])
|
||||
}
|
||||
|
||||
// validateFinalMaskJSONSalamander checks a stored whole finalmask: a host's, or the subscription's.
|
||||
func validateFinalMaskJSONSalamander(finalmask string) error {
|
||||
var fm map[string]any
|
||||
if json.Unmarshal([]byte(finalmask), &fm) != nil {
|
||||
return nil
|
||||
}
|
||||
return maskcompat.CheckSalamanderPasswords(fm)
|
||||
}
|
||||
|
||||
// normalizeMtprotoSecret rebuilds every mtproto client's FakeTLS secret so it is
|
||||
// always valid before the row is persisted, and drops the vestigial inbound-level
|
||||
// secret and adTag: MTProto is multi-client, so mtg and every share link read
|
||||
@@ -1156,6 +1175,9 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, boo
|
||||
if err := validateFinalMaskXmcProfiles(inbound.StreamSettings); err != nil {
|
||||
return inbound, false, err
|
||||
}
|
||||
if err := validateFinalMaskSalamander(inbound.StreamSettings); err != nil {
|
||||
return inbound, false, err
|
||||
}
|
||||
s.normalizeMtprotoSecret(inbound)
|
||||
if err := s.normalizeMtprotoXrayPort(inbound, ""); err != nil {
|
||||
return inbound, false, err
|
||||
@@ -1798,6 +1820,9 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||
if err := validateFinalMaskXmcProfiles(inbound.StreamSettings); err != nil {
|
||||
return inbound, false, err
|
||||
}
|
||||
if err := validateFinalMaskSalamander(inbound.StreamSettings); err != nil {
|
||||
return inbound, false, err
|
||||
}
|
||||
s.normalizeMtprotoSecret(inbound)
|
||||
|
||||
oldInbound, err := s.GetInbound(inbound.Id)
|
||||
|
||||
Reference in New Issue
Block a user