mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-11 23:26:07 +00:00
fix(clients): reject spaces, '/', '\' and control chars in subscription ID
Like the client email, the subId is embedded directly in subscription URLs, so the same characters break it. Validate it on the backend (Create + Update) and the frontend (Zod), with a localized message across all 13 locales. An empty subId stays allowed (it is then auto-generated).
This commit is contained in:
+23
-3
@@ -408,12 +408,26 @@ type ClientCreatePayload struct {
|
||||
InboundIds []int `json:"inboundIds"`
|
||||
}
|
||||
|
||||
func validateClientEmail(email string) error {
|
||||
for _, r := range email {
|
||||
func hasForbiddenClientChar(s string) bool {
|
||||
for _, r := range s {
|
||||
if r == '/' || r == '\\' || r == ' ' || r < 0x20 || r == 0x7f {
|
||||
return common.NewError("client email contains an invalid character:", email)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validateClientEmail(email string) error {
|
||||
if hasForbiddenClientChar(email) {
|
||||
return common.NewError("client email contains an invalid character:", email)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateClientSubID(subID string) error {
|
||||
if hasForbiddenClientChar(subID) {
|
||||
return common.NewError("client subId contains an invalid character:", subID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -428,6 +442,9 @@ func (s *ClientService) Create(inboundSvc *InboundService, payload *ClientCreate
|
||||
if err := validateClientEmail(client.Email); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := validateClientSubID(client.SubID); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(payload.InboundIds) == 0 {
|
||||
return false, common.NewError("at least one inbound is required")
|
||||
}
|
||||
@@ -596,6 +613,9 @@ func (s *ClientService) Update(inboundSvc *InboundService, id int, updated model
|
||||
if err := validateClientEmail(updated.Email); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := validateClientSubID(updated.SubID); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if updated.SubID == "" {
|
||||
updated.SubID = existing.SubID
|
||||
}
|
||||
|
||||
@@ -30,3 +30,28 @@ func TestValidateClientEmail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateClientSubID(t *testing.T) {
|
||||
valid := []string{
|
||||
"",
|
||||
"abc123",
|
||||
"sub-id_value",
|
||||
}
|
||||
for _, subID := range valid {
|
||||
if err := validateClientSubID(subID); err != nil {
|
||||
t.Errorf("validateClientSubID(%q) = %v, want nil", subID, err)
|
||||
}
|
||||
}
|
||||
|
||||
invalid := []string{
|
||||
"a/b",
|
||||
"with space",
|
||||
"back\\slash",
|
||||
"new\nline",
|
||||
}
|
||||
for _, subID := range invalid {
|
||||
if err := validateClientSubID(subID); err == nil {
|
||||
t.Errorf("validateClientSubID(%q) = nil, want error", subID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user