Ensure VLESS users include encryption field (#588)

This commit is contained in:
shenlan 2025-10-27 02:23:12 +08:00 committed by GitHub
parent 80b0b12dc0
commit ef2e4088ef
3 changed files with 38 additions and 19 deletions

View File

@ -14,14 +14,19 @@ const (
// DefaultFlow is applied to VLESS clients when no explicit flow is
// provided. It matches the tlsSettings baked into the template.
DefaultFlow = "xtls-rprx-vision"
// DefaultEncryption is required by Xray for all VLESS users in the
// outbound array.
DefaultEncryption = "none"
)
// Client represents an entry under outbounds[].settings.vnext[].users[] in the Xray
// config.
type Client struct {
ID string
Email string
Flow string
ID string
Email string
Flow string
Encryption string
}
// Generator updates the Xray configuration file based on a template and a set of
@ -111,6 +116,11 @@ func replaceClients(root map[string]interface{}, clients []Client) error {
flow = DefaultFlow
}
entry["flow"] = flow
encryption := strings.TrimSpace(client.Encryption)
if encryption == "" {
encryption = DefaultEncryption
}
entry["encryption"] = encryption
clientObjects = append(clientObjects, entry)
}

View File

@ -13,9 +13,10 @@ type testConfig struct {
Settings struct {
VNext []struct {
Users []struct {
ID string `json:"id"`
Email string `json:"email,omitempty"`
Flow string `json:"flow,omitempty"`
ID string `json:"id"`
Email string `json:"email,omitempty"`
Flow string `json:"flow,omitempty"`
Encryption string `json:"encryption"`
} `json:"users"`
Address string `json:"address"`
} `json:"vnext"`
@ -57,7 +58,7 @@ func TestGeneratorGenerate(t *testing.T) {
}
clients := []Client{
{ID: "uuid-a", Email: "a@demo", Flow: "xtls-rprx-vision"},
{ID: "uuid-a", Email: "a@demo", Flow: "xtls-rprx-vision", Encryption: "custom"},
{ID: "uuid-b"},
}
@ -94,7 +95,10 @@ func TestGeneratorGenerate(t *testing.T) {
if gotUsers[0].Flow != "xtls-rprx-vision" {
t.Fatalf("unexpected first user flow: %+v", gotUsers[0])
}
if gotUsers[1].ID != "uuid-b" || gotUsers[1].Email != "" || gotUsers[1].Flow != DefaultFlow {
if gotUsers[0].Encryption != "custom" {
t.Fatalf("unexpected first user encryption: %+v", gotUsers[0])
}
if gotUsers[1].ID != "uuid-b" || gotUsers[1].Email != "" || gotUsers[1].Flow != DefaultFlow || gotUsers[1].Encryption != DefaultEncryption {
t.Fatalf("unexpected second user: %+v", gotUsers[1])
}
}

View File

@ -19,12 +19,13 @@ The XControl platform manages access to an Xray proxy node that exposes a single
## Data Model
| Field | Source | Notes |
|--------------|---------------|-----------------------------------------------------------|
| `id` | Account table | Stored as UUID v4 for compatibility with Xray clients. |
| `email` | Account table | Optional identifier; used for auditing and debugging. |
| `flow` | Derived | Optional; defaults to `xtls-rprx-vision` for Vision mode. |
| `enabled` | Account table | Only enabled users contribute to the generated array. |
| Field | Source | Notes |
|--------------|---------------|------------------------------------------------------------------------|
| `id` | Account table | Stored as UUID v4 for compatibility with Xray clients. |
| `email` | Account table | Optional identifier; used for auditing and debugging. |
| `flow` | Derived | Optional; defaults to `xtls-rprx-vision` for Vision mode. |
| `encryption` | Derived | Required by Xray; defaults to `none` when not explicitly configured. |
| `enabled` | Account table | Only enabled users contribute to the generated array. |
The backend queries all enabled accounts and materializes the JSON payload expected by Xray.
@ -54,8 +55,8 @@ The backend queries all enabled accounts and materializes the JSON payload expec
4. **Generate Configuration**:
- Load the base template for `/usr/local/etc/xray/config.json`.
- Replace the `outbounds[].settings.vnext[].users[]` node with the freshly computed array. New registrations simply append to the
slice composed in memory before the generator writes it back. Each client entry includes the UUID, optional email, and any
flow directive required by the transport profile.
slice composed in memory before the generator writes it back. Each client entry includes the UUID, optional email, required `encryption`
flag (defaulting to `none`), and any flow directive required by the transport profile.
- Persist the resulting JSON atomically (write to temp file then move into place).
5. **Validate JSON**:
- Run `jq . /usr/local/etc/xray/config.json` or an equivalent Go `json.Unmarshal` check to confirm syntax correctness.
@ -72,9 +73,10 @@ The backend queries all enabled accounts and materializes the JSON payload expec
```go
// Client represents an entry in outbounds[].settings.vnext[].users[].
type Client struct {
ID string `json:"id"`
Email string `json:"email"`
Flow string `json:"flow"`
ID string `json:"id"`
Email string `json:"email"`
Flow string `json:"flow"`
Encryption string `json:"encryption"`
}
func SyncXrayClients(ctx context.Context, db *sql.DB, fs afero.Fs, runner command.Runner) error {
@ -93,6 +95,9 @@ func SyncXrayClients(ctx context.Context, db *sql.DB, fs afero.Fs, runner comman
if cfg.Outbounds[0].Settings.VNext[0].Users[i].Flow == "" {
cfg.Outbounds[0].Settings.VNext[0].Users[i].Flow = "xtls-rprx-vision"
}
if cfg.Outbounds[0].Settings.VNext[0].Users[i].Encryption == "" {
cfg.Outbounds[0].Settings.VNext[0].Users[i].Encryption = "none"
}
}
buf, err := json.MarshalIndent(cfg, "", " ")