|
@@ -299,9 +299,7 @@ func (s *ClientService) ListForInbound(tx *gorm.DB, inboundId int) ([]model.Clie
|
|
|
out := make([]model.Client, 0, len(rows))
|
|
out := make([]model.Client, 0, len(rows))
|
|
|
for i := range rows {
|
|
for i := range rows {
|
|
|
c := rows[i].ToClient()
|
|
c := rows[i].ToClient()
|
|
|
- if rows[i].FlowOverride != "" {
|
|
|
|
|
- c.Flow = rows[i].FlowOverride
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ c.Flow = rows[i].FlowOverride
|
|
|
out = append(out, *c)
|
|
out = append(out, *c)
|
|
|
}
|
|
}
|
|
|
return out, nil
|
|
return out, nil
|
|
@@ -455,7 +453,7 @@ func (s *ClientService) Create(inboundSvc *InboundService, payload *ClientCreate
|
|
|
if err := s.fillProtocolDefaults(&client, inbound); err != nil {
|
|
if err := s.fillProtocolDefaults(&client, inbound); err != nil {
|
|
|
return needRestart, err
|
|
return needRestart, err
|
|
|
}
|
|
}
|
|
|
- settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {client}})
|
|
|
|
|
|
|
+ settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {clientWithInboundFlow(client, inbound)}})
|
|
|
if mErr != nil {
|
|
if mErr != nil {
|
|
|
return needRestart, mErr
|
|
return needRestart, mErr
|
|
|
}
|
|
}
|
|
@@ -496,8 +494,13 @@ func (s *ClientService) fillProtocolDefaults(c *model.Client, ib *model.Inbound)
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// shadowsocksMethodFromSettings pulls the "method" field out of the inbound's
|
|
|
|
|
-// settings JSON. Returns "" when the field is missing or settings is invalid.
|
|
|
|
|
|
|
+func clientWithInboundFlow(c model.Client, ib *model.Inbound) model.Client {
|
|
|
|
|
+ if !inboundCanEnableTlsFlow(string(ib.Protocol), ib.StreamSettings) {
|
|
|
|
|
+ c.Flow = ""
|
|
|
|
|
+ }
|
|
|
|
|
+ return c
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func shadowsocksMethodFromSettings(settings string) string {
|
|
func shadowsocksMethodFromSettings(settings string) string {
|
|
|
if settings == "" {
|
|
if settings == "" {
|
|
|
return ""
|
|
return ""
|
|
@@ -510,11 +513,6 @@ func shadowsocksMethodFromSettings(settings string) string {
|
|
|
return method
|
|
return method
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// randomShadowsocksClientKey returns a per-client key sized to the cipher.
|
|
|
|
|
-// The 2022-blake3 ciphers require a base64-encoded key of an exact byte
|
|
|
|
|
-// length (16 bytes for aes-128-gcm, 32 bytes for aes-256-gcm and
|
|
|
|
|
-// chacha20-poly1305) — anything else fails with "bad key" on xray start.
|
|
|
|
|
-// Older ciphers accept arbitrary passwords, so we keep the uuid-style.
|
|
|
|
|
func randomShadowsocksClientKey(method string) string {
|
|
func randomShadowsocksClientKey(method string) string {
|
|
|
if n := shadowsocksKeyBytes(method); n > 0 {
|
|
if n := shadowsocksKeyBytes(method); n > 0 {
|
|
|
return random.Base64Bytes(n)
|
|
return random.Base64Bytes(n)
|
|
@@ -522,9 +520,6 @@ func randomShadowsocksClientKey(method string) string {
|
|
|
return strings.ReplaceAll(uuid.NewString(), "-", "")
|
|
return strings.ReplaceAll(uuid.NewString(), "-", "")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// validShadowsocksClientKey reports whether key is acceptable for the cipher.
|
|
|
|
|
-// For 2022-blake3 it must decode to the exact byte length the cipher needs;
|
|
|
|
|
-// any other method accepts any non-empty string.
|
|
|
|
|
func validShadowsocksClientKey(method, key string) bool {
|
|
func validShadowsocksClientKey(method, key string) bool {
|
|
|
n := shadowsocksKeyBytes(method)
|
|
n := shadowsocksKeyBytes(method)
|
|
|
if n == 0 {
|
|
if n == 0 {
|
|
@@ -547,13 +542,6 @@ func shadowsocksKeyBytes(method string) int {
|
|
|
return 0
|
|
return 0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// applyShadowsocksClientMethod normalises the per-client "method" field
|
|
|
|
|
-// when an inbound is created or updated:
|
|
|
|
|
-// - Legacy ciphers: backfill `method` so xray's multi-user code is happy.
|
|
|
|
|
-// "unsupported cipher method:" otherwise.
|
|
|
|
|
-// - 2022-blake3-*: strip the per-client `method` because xray rejects
|
|
|
|
|
-// it with "users must have empty method". This matters after an admin
|
|
|
|
|
-// switches an existing inbound from a legacy cipher to a 2022 one.
|
|
|
|
|
func applyShadowsocksClientMethod(clients []any, settings map[string]any) {
|
|
func applyShadowsocksClientMethod(clients []any, settings map[string]any) {
|
|
|
method, _ := settings["method"].(string)
|
|
method, _ := settings["method"].(string)
|
|
|
is2022 := strings.HasPrefix(method, "2022-blake3-")
|
|
is2022 := strings.HasPrefix(method, "2022-blake3-")
|
|
@@ -604,10 +592,6 @@ func (s *ClientService) Update(inboundSvc *InboundService, id int, updated model
|
|
|
updated.CreatedAt = existing.CreatedAt
|
|
updated.CreatedAt = existing.CreatedAt
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Rename the ClientRecord row up front when the email changes. SyncInbound
|
|
|
|
|
- // (invoked from UpdateInboundClient below) looks up by email — without
|
|
|
|
|
- // renaming first it would treat the new email as a brand-new client,
|
|
|
|
|
- // insert a duplicate ClientRecord, and leave the original orphaned.
|
|
|
|
|
if updated.Email != existing.Email {
|
|
if updated.Email != existing.Email {
|
|
|
var collisionCount int64
|
|
var collisionCount int64
|
|
|
if err := database.GetDB().Model(&model.ClientRecord{}).
|
|
if err := database.GetDB().Model(&model.ClientRecord{}).
|
|
@@ -646,7 +630,7 @@ func (s *ClientService) Update(inboundSvc *InboundService, id int, updated model
|
|
|
if err := s.fillProtocolDefaults(&updated, inbound); err != nil {
|
|
if err := s.fillProtocolDefaults(&updated, inbound); err != nil {
|
|
|
return needRestart, err
|
|
return needRestart, err
|
|
|
}
|
|
}
|
|
|
- settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {updated}})
|
|
|
|
|
|
|
+ settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {clientWithInboundFlow(updated, inbound)}})
|
|
|
if mErr != nil {
|
|
if mErr != nil {
|
|
|
return needRestart, mErr
|
|
return needRestart, mErr
|
|
|
}
|
|
}
|
|
@@ -752,7 +736,7 @@ func (s *ClientService) Attach(inboundSvc *InboundService, id int, inboundIds []
|
|
|
if err := s.fillProtocolDefaults(©Client, inbound); err != nil {
|
|
if err := s.fillProtocolDefaults(©Client, inbound); err != nil {
|
|
|
return needRestart, err
|
|
return needRestart, err
|
|
|
}
|
|
}
|
|
|
- settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {copyClient}})
|
|
|
|
|
|
|
+ settingsPayload, mErr := json.Marshal(map[string][]model.Client{"clients": {clientWithInboundFlow(copyClient, inbound)}})
|
|
|
if mErr != nil {
|
|
if mErr != nil {
|
|
|
return needRestart, mErr
|
|
return needRestart, mErr
|
|
|
}
|
|
}
|
|
@@ -870,7 +854,7 @@ func (s *ClientService) BulkAttach(inboundSvc *InboundService, emails []string,
|
|
|
recordErr("%s -> inbound %d: %v", rec.Email, ibId, err)
|
|
recordErr("%s -> inbound %d: %v", rec.Email, ibId, err)
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
- clientsToAdd = append(clientsToAdd, client)
|
|
|
|
|
|
|
+ clientsToAdd = append(clientsToAdd, clientWithInboundFlow(client, inbound))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if len(clientsToAdd) == 0 {
|
|
if len(clientsToAdd) == 0 {
|