From 9da9678bae2966ebd18edbe8a99ceed97c3cddcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 28 Sep 2026 03:37:16 +0800 Subject: [PATCH] Format plural list options as arrays --- .../httpclient/apple_transport_darwin_test.go | 4 +- docs/schema.json | 417 +++++------------- option/acme.go | 10 +- option/hysteria.go | 2 +- option/hysteria2.go | 18 +- option/openvpn.go | 40 +- option/route.go | 2 +- option/ssh.go | 2 +- option/tailscale.go | 2 +- option/tls.go | 96 ++-- option/types.go | 17 + option/wireguard.go | 14 +- 12 files changed, 226 insertions(+), 398 deletions(-) diff --git a/common/httpclient/apple_transport_darwin_test.go b/common/httpclient/apple_transport_darwin_test.go index 272e8f1ba..e466a9501 100644 --- a/common/httpclient/apple_transport_darwin_test.go +++ b/common/httpclient/apple_transport_darwin_test.go @@ -247,7 +247,7 @@ func TestNewAppleSessionConfig(t *testing.T) { options: option.HTTPClientOptions{ OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ TLS: &option.OutboundTLSOptions{ - CipherSuites: badoption.Listable[string]{"TLS_AES_128_GCM_SHA256"}, + CipherSuites: option.LegacyListable[string]{"TLS_AES_128_GCM_SHA256"}, }, }, }, @@ -258,7 +258,7 @@ func TestNewAppleSessionConfig(t *testing.T) { options: option.HTTPClientOptions{ OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{ TLS: &option.OutboundTLSOptions{ - CurvePreferences: badoption.Listable[option.CurvePreference]{option.CurvePreference(option.X25519)}, + CurvePreferences: option.LegacyListable[option.CurvePreference]{option.CurvePreference(option.X25519)}, }, }, }, diff --git a/docs/schema.json b/docs/schema.json index 96107d144..b4ec3f83e 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -153,17 +153,10 @@ "$ref": "#/$defs/Duration" }, "resolvers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "override_domain": { "type": "string" @@ -202,17 +195,10 @@ "$ref": "#/$defs/Duration" }, "resolvers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "override_domain": { "type": "string" @@ -245,17 +231,10 @@ "$ref": "#/$defs/Duration" }, "resolvers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "override_domain": { "type": "string" @@ -3946,17 +3925,10 @@ "type": "string" }, "data_ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "data_ciphers_fallback": { "type": "string" @@ -4035,17 +4007,10 @@ } }, "routes": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "route_gateway": { "type": "string" @@ -4057,17 +4022,10 @@ "type": "boolean" }, "redirect_gateway_flags": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "redirect_private": { "type": "boolean" @@ -4307,17 +4265,10 @@ "type": "string" }, "data_ciphers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "data_ciphers_fallback": { "type": "string" @@ -4522,17 +4473,10 @@ "type": "boolean" }, "advertise_tags": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "listen_port": { "type": "integer", @@ -5582,17 +5526,10 @@ "type": "string" }, "stun_servers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "ip_version": { "type": "integer", @@ -5627,17 +5564,10 @@ "type": "string" }, "stun_servers": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "ip_version": { "type": "integer", @@ -8351,44 +8281,23 @@ ] }, "cipher_suites": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "curve_preferences": { - "anyOf": [ - { - "type": "string", - "enum": [ - "P256", - "P384", - "P521", - "X25519", - "X25519MLKEM768" - ] - }, - { - "type": "array", - "items": { - "type": "string", - "enum": [ - "P256", - "P384", - "P521", - "X25519", - "X25519MLKEM768" - ] - } - } - ] + "type": "array", + "items": { + "type": "string", + "enum": [ + "P256", + "P384", + "P521", + "X25519", + "X25519MLKEM768" + ] + } }, "certificate": { "anyOf": [ @@ -10558,30 +10467,16 @@ "type": "integer" }, "addresses": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "resolve_domains": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "dnssec": { "type": "string", @@ -10609,17 +10504,10 @@ "type": "object", "properties": { "routes": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "dns": { "anyOf": [ @@ -10641,46 +10529,25 @@ } }, "search_domains": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "dhcp_options": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "redirect_gateway": { "type": "boolean" }, "redirect_gateway_flags": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "block_outside_dns": { "type": "boolean" @@ -11271,17 +11138,10 @@ "maximum": 65535 }, "server_ports": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "hop_interval": { "$ref": "#/$defs/Duration" @@ -11519,17 +11379,10 @@ "maximum": 65535 }, "server_ports": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "hop_interval": { "$ref": "#/$defs/Duration" @@ -12906,17 +12759,10 @@ ] }, "host_key_algorithms": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "client_version": { "type": "string" @@ -13990,44 +13836,23 @@ ] }, "cipher_suites": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "curve_preferences": { - "anyOf": [ - { - "type": "string", - "enum": [ - "P256", - "P384", - "P521", - "X25519", - "X25519MLKEM768" - ] - }, - { - "type": "array", - "items": { - "type": "string", - "enum": [ - "P256", - "P384", - "P521", - "X25519", - "X25519MLKEM768" - ] - } - } - ] + "type": "array", + "items": { + "type": "string", + "enum": [ + "P256", + "P384", + "P521", + "X25519", + "X25519MLKEM768" + ] + } }, "certificate": { "anyOf": [ @@ -14212,17 +14037,10 @@ "type": "boolean" }, "dhcp_lease_files": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "auto_detect_interface": { "type": "boolean" @@ -17333,17 +17151,10 @@ "type": "string" }, "allowed_ips": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } }, "persistent_keepalive_interval": { "type": "integer", diff --git a/option/acme.go b/option/acme.go index fe6c1221f..897c86e8f 100644 --- a/option/acme.go +++ b/option/acme.go @@ -39,11 +39,11 @@ type _ACMEProviderDNS01ChallengeOptions struct { } type AbstractACMEProviderDNS01ChallengeOptions struct { - TTL badoption.Duration `json:"ttl,omitempty"` - PropagationDelay badoption.Duration `json:"propagation_delay,omitempty"` - PropagationTimeout badoption.Duration `json:"propagation_timeout,omitempty"` - Resolvers badoption.Listable[string] `json:"resolvers,omitempty"` - OverrideDomain string `json:"override_domain,omitempty"` + TTL badoption.Duration `json:"ttl,omitempty"` + PropagationDelay badoption.Duration `json:"propagation_delay,omitempty"` + PropagationTimeout badoption.Duration `json:"propagation_timeout,omitempty"` + Resolvers LegacyListable[string] `json:"resolvers,omitempty"` + OverrideDomain string `json:"override_domain,omitempty"` } type ACMEProviderDNS01ChallengeOptions _ACMEProviderDNS01ChallengeOptions diff --git a/option/hysteria.go b/option/hysteria.go index d1b9ad30a..dfa43ab43 100644 --- a/option/hysteria.go +++ b/option/hysteria.go @@ -34,7 +34,7 @@ type HysteriaUser struct { type HysteriaOutboundOptions struct { DialerOptions ServerOptions - ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"` + ServerPorts LegacyListable[string] `json:"server_ports,omitempty"` HopInterval badoption.Duration `json:"hop_interval,omitempty"` Up *byteformats.NetworkBytesCompat `json:"up,omitempty"` UpMbps int `json:"up_mbps,omitempty"` diff --git a/option/hysteria2.go b/option/hysteria2.go index 237109b2e..0ead7add4 100644 --- a/option/hysteria2.go +++ b/option/hysteria2.go @@ -33,7 +33,7 @@ type Hysteria2Realm struct { ServerURL string `json:"server_url"` Token string `json:"token,omitempty"` RealmID string `json:"realm_id"` - STUNServers badoption.Listable[string] `json:"stun_servers"` + STUNServers LegacyListable[string] `json:"stun_servers"` IPVersion int `json:"ip_version,omitempty" enum:"0,4,6"` PortMapping *Hysteria2RealmPortMapping `json:"port_mapping,omitempty"` HTTPClient *HTTPClientOptions `json:"http_client,omitempty"` @@ -210,14 +210,14 @@ type Hysteria2MasqueradeString struct { type Hysteria2OutboundOptions struct { DialerOptions ServerOptions - ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"` - HopInterval badoption.Duration `json:"hop_interval,omitempty"` - HopIntervalMax badoption.Duration `json:"hop_interval_max,omitempty"` - UpMbps int `json:"up_mbps,omitempty"` - DownMbps int `json:"down_mbps,omitempty"` - Obfs *Hysteria2Obfs `json:"obfs,omitempty"` - Password string `json:"password,omitempty"` - Network NetworkList `json:"network,omitempty"` + ServerPorts LegacyListable[string] `json:"server_ports,omitempty"` + HopInterval badoption.Duration `json:"hop_interval,omitempty"` + HopIntervalMax badoption.Duration `json:"hop_interval_max,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs *Hysteria2Obfs `json:"obfs,omitempty"` + Password string `json:"password,omitempty"` + Network NetworkList `json:"network,omitempty"` OutboundTLSOptionsContainer QUICOptions BBRProfile string `json:"bbr_profile,omitempty" enum:"standard,conservative,aggressive"` diff --git a/option/openvpn.go b/option/openvpn.go index d62aaf980..80ad31f39 100644 --- a/option/openvpn.go +++ b/option/openvpn.go @@ -38,7 +38,7 @@ type OpenVPNClientEndpointOptions struct { KeyDirection string `json:"key_direction,omitempty" enum:"server,client"` TLS *OpenVPNOutboundTLSOptions `json:"tls,omitempty"` Cipher string `json:"cipher,omitempty"` - DataCiphers badoption.Listable[string] `json:"data_ciphers,omitempty"` + DataCiphers LegacyListable[string] `json:"data_ciphers,omitempty"` DataCiphersFallback string `json:"data_ciphers_fallback,omitempty"` Auth string `json:"auth,omitempty"` MSSFix uint32 `json:"mss_fix,omitempty"` @@ -52,11 +52,11 @@ type OpenVPNClientEndpointOptions struct { AllowCompression string `json:"allow_compression,omitempty" enum:"no,asym,yes"` RouteNoPull bool `json:"route_no_pull,omitempty"` PullFilters []OpenVPNPullFilterOptions `json:"pull_filters,omitempty"` - Routes badoption.Listable[netip.Prefix] `json:"routes,omitempty"` + Routes LegacyListable[netip.Prefix] `json:"routes,omitempty"` RouteGateway *badoption.Addr `json:"route_gateway,omitempty"` RouteMetric int `json:"route_metric,omitempty"` RedirectGateway bool `json:"redirect_gateway,omitempty"` - RedirectGatewayFlags badoption.Listable[string] `json:"redirect_gateway_flags,omitempty"` + RedirectGatewayFlags LegacyListable[string] `json:"redirect_gateway_flags,omitempty"` RedirectPrivate bool `json:"redirect_private,omitempty"` BlockIPv6 bool `json:"block_ipv6,omitempty"` PingInterval badoption.Duration `json:"ping_interval,omitempty"` @@ -91,7 +91,7 @@ type OpenVPNServerEndpointOptions struct { KeyDirection string `json:"key_direction,omitempty" enum:"server,client"` TLS *OpenVPNInboundTLSOptions `json:"tls,omitempty"` Cipher string `json:"cipher,omitempty"` - DataCiphers badoption.Listable[string] `json:"data_ciphers,omitempty"` + DataCiphers LegacyListable[string] `json:"data_ciphers,omitempty"` DataCiphersFallback string `json:"data_ciphers_fallback,omitempty"` Auth string `json:"auth,omitempty"` MSSFix uint32 `json:"mss_fix,omitempty"` @@ -182,25 +182,25 @@ type OpenVPNInboundControlWrapOptions struct { } type OpenVPNPushOptions struct { - Routes badoption.Listable[netip.Prefix] `json:"routes,omitempty"` - DNS badoption.Listable[netip.Addr] `json:"dns,omitempty"` - DNSServers []OpenVPNPushDNSServerOptions `json:"dns_servers,omitempty"` - SearchDomains badoption.Listable[string] `json:"search_domains,omitempty"` - DHCPOptions badoption.Listable[string] `json:"dhcp_options,omitempty"` - RedirectGateway bool `json:"redirect_gateway,omitempty"` - RedirectGatewayFlags badoption.Listable[string] `json:"redirect_gateway_flags,omitempty"` - BlockOutsideDNS bool `json:"block_outside_dns,omitempty"` - PingInterval badoption.Duration `json:"ping_interval,omitempty"` - PingRestart badoption.Duration `json:"ping_restart,omitempty"` + Routes LegacyListable[netip.Prefix] `json:"routes,omitempty"` + DNS badoption.Listable[netip.Addr] `json:"dns,omitempty"` + DNSServers []OpenVPNPushDNSServerOptions `json:"dns_servers,omitempty"` + SearchDomains LegacyListable[string] `json:"search_domains,omitempty"` + DHCPOptions LegacyListable[string] `json:"dhcp_options,omitempty"` + RedirectGateway bool `json:"redirect_gateway,omitempty"` + RedirectGatewayFlags LegacyListable[string] `json:"redirect_gateway_flags,omitempty"` + BlockOutsideDNS bool `json:"block_outside_dns,omitempty"` + PingInterval badoption.Duration `json:"ping_interval,omitempty"` + PingRestart badoption.Duration `json:"ping_restart,omitempty"` } type OpenVPNPushDNSServerOptions struct { - Priority int `json:"priority"` - Addresses badoption.Listable[string] `json:"addresses"` - ResolveDomains badoption.Listable[string] `json:"resolve_domains,omitempty"` - DNSSEC string `json:"dnssec,omitempty" enum:"yes,optional,no"` - Transport string `json:"transport,omitempty" enum:"plain,dot,doh"` - SNI string `json:"sni,omitempty"` + Priority int `json:"priority"` + Addresses LegacyListable[string] `json:"addresses"` + ResolveDomains LegacyListable[string] `json:"resolve_domains,omitempty"` + DNSSEC string `json:"dnssec,omitempty" enum:"yes,optional,no"` + Transport string `json:"transport,omitempty" enum:"plain,dot,doh"` + SNI string `json:"sni,omitempty"` } type OpenVPNDNSServerOptions struct { diff --git a/option/route.go b/option/route.go index 39f3cfb9d..2d7c732e6 100644 --- a/option/route.go +++ b/option/route.go @@ -10,7 +10,7 @@ type RouteOptions struct { Final string `json:"final,omitempty" reference:"outbound"` FindProcess bool `json:"find_process,omitempty"` FindNeighbor bool `json:"find_neighbor,omitempty"` - DHCPLeaseFiles badoption.Listable[string] `json:"dhcp_lease_files,omitempty"` + DHCPLeaseFiles LegacyListable[string] `json:"dhcp_lease_files,omitempty"` AutoDetectInterface bool `json:"auto_detect_interface,omitempty"` OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"` DefaultInterface string `json:"default_interface,omitempty"` diff --git a/option/ssh.go b/option/ssh.go index 8ead4f670..96727f9b4 100644 --- a/option/ssh.go +++ b/option/ssh.go @@ -11,7 +11,7 @@ type SSHOutboundOptions struct { PrivateKeyPath string `json:"private_key_path,omitempty"` PrivateKeyPassphrase string `json:"private_key_passphrase,omitempty"` HostKey badoption.Listable[string] `json:"host_key,omitempty"` - HostKeyAlgorithms badoption.Listable[string] `json:"host_key_algorithms,omitempty"` + HostKeyAlgorithms LegacyListable[string] `json:"host_key_algorithms,omitempty"` ClientVersion string `json:"client_version,omitempty"` Cipher badoption.Listable[string] `json:"cipher,omitempty"` MAC badoption.Listable[string] `json:"mac,omitempty"` diff --git a/option/tailscale.go b/option/tailscale.go index 1142b2e05..fe14c0782 100644 --- a/option/tailscale.go +++ b/option/tailscale.go @@ -24,7 +24,7 @@ type TailscaleEndpointOptions struct { ExitNodeAllowLANAccess bool `json:"exit_node_allow_lan_access,omitempty"` AdvertiseRoutes []netip.Prefix `json:"advertise_routes,omitempty"` AdvertiseExitNode bool `json:"advertise_exit_node,omitempty"` - AdvertiseTags badoption.Listable[string] `json:"advertise_tags,omitempty"` + AdvertiseTags LegacyListable[string] `json:"advertise_tags,omitempty"` ListenPort uint16 `json:"listen_port,omitempty"` RelayServerPort *uint16 `json:"relay_server_port,omitempty"` RelayServerStaticEndpoints []netip.AddrPort `json:"relay_server_static_endpoints,omitempty"` diff --git a/option/tls.go b/option/tls.go index 5c807d676..b193da5e4 100644 --- a/option/tls.go +++ b/option/tls.go @@ -11,26 +11,26 @@ import ( ) type InboundTLSOptions struct { - Enabled bool `json:"enabled,omitempty"` - ServerName string `json:"server_name,omitempty"` - Insecure bool `json:"insecure,omitempty"` - ALPN badoption.Listable[string] `json:"alpn,omitempty" examples:"http/1.1,h2,h3"` - MinVersion string `json:"min_version,omitempty" enum:"1.0,1.1,1.2,1.3"` - MaxVersion string `json:"max_version,omitempty" enum:"1.0,1.1,1.2,1.3"` - CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"` - CurvePreferences badoption.Listable[CurvePreference] `json:"curve_preferences,omitempty"` - Certificate badoption.Listable[string] `json:"certificate,omitempty"` - CertificatePath string `json:"certificate_path,omitempty"` - ClientAuthentication ClientAuthType `json:"client_authentication,omitempty"` - ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"` - ClientCertificatePath badoption.Listable[string] `json:"client_certificate_path,omitempty"` - ClientCertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"client_certificate_public_key_sha256,omitempty"` - Key badoption.Listable[string] `json:"key,omitempty"` - KeyPath string `json:"key_path,omitempty"` - KernelTx bool `json:"kernel_tx,omitempty"` - KernelRx bool `json:"kernel_rx,omitempty"` - HandshakeTimeout badoption.Duration `json:"handshake_timeout,omitempty"` - CertificateProvider *CertificateProviderOptions `json:"certificate_provider,omitempty"` + Enabled bool `json:"enabled,omitempty"` + ServerName string `json:"server_name,omitempty"` + Insecure bool `json:"insecure,omitempty"` + ALPN badoption.Listable[string] `json:"alpn,omitempty" examples:"http/1.1,h2,h3"` + MinVersion string `json:"min_version,omitempty" enum:"1.0,1.1,1.2,1.3"` + MaxVersion string `json:"max_version,omitempty" enum:"1.0,1.1,1.2,1.3"` + CipherSuites LegacyListable[string] `json:"cipher_suites,omitempty"` + CurvePreferences LegacyListable[CurvePreference] `json:"curve_preferences,omitempty"` + Certificate badoption.Listable[string] `json:"certificate,omitempty"` + CertificatePath string `json:"certificate_path,omitempty"` + ClientAuthentication ClientAuthType `json:"client_authentication,omitempty"` + ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"` + ClientCertificatePath badoption.Listable[string] `json:"client_certificate_path,omitempty"` + ClientCertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"client_certificate_public_key_sha256,omitempty"` + Key badoption.Listable[string] `json:"key,omitempty"` + KeyPath string `json:"key_path,omitempty"` + KernelTx bool `json:"kernel_tx,omitempty"` + KernelRx bool `json:"kernel_rx,omitempty"` + HandshakeTimeout badoption.Duration `json:"handshake_timeout,omitempty"` + CertificateProvider *CertificateProviderOptions `json:"certificate_provider,omitempty"` // Deprecated: use certificate_provider ACME *InboundACMEOptions `json:"acme,omitempty" schema:"omit"` @@ -105,34 +105,34 @@ func (o *InboundTLSOptionsContainer) ReplaceInboundTLSOptions(options *InboundTL } type OutboundTLSOptions struct { - Enabled bool `json:"enabled,omitempty"` - Engine string `json:"engine,omitempty" enum:"go,apple,windows"` - DisableSNI bool `json:"disable_sni,omitempty"` - ServerName string `json:"server_name,omitempty"` - Insecure bool `json:"insecure,omitempty"` - ALPN badoption.Listable[string] `json:"alpn,omitempty" examples:"http/1.1,h2,h3"` - MinVersion string `json:"min_version,omitempty" enum:"1.0,1.1,1.2,1.3"` - MaxVersion string `json:"max_version,omitempty" enum:"1.0,1.1,1.2,1.3"` - CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"` - CurvePreferences badoption.Listable[CurvePreference] `json:"curve_preferences,omitempty"` - Certificate badoption.Listable[string] `json:"certificate,omitempty"` - CertificatePath string `json:"certificate_path,omitempty"` - CertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"certificate_public_key_sha256,omitempty"` - ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"` - ClientCertificatePath string `json:"client_certificate_path,omitempty"` - ClientKey badoption.Listable[string] `json:"client_key,omitempty"` - ClientKeyPath string `json:"client_key_path,omitempty"` - Fragment bool `json:"fragment,omitempty"` - FragmentFallbackDelay badoption.Duration `json:"fragment_fallback_delay,omitempty"` - RecordFragment bool `json:"record_fragment,omitempty"` - Spoof string `json:"spoof,omitempty"` - SpoofMethod string `json:"spoof_method,omitempty" enum:"wrong-sequence,wrong-checksum,wrong-ack,wrong-md5,wrong-timestamp"` - KernelTx bool `json:"kernel_tx,omitempty"` - KernelRx bool `json:"kernel_rx,omitempty"` - HandshakeTimeout badoption.Duration `json:"handshake_timeout,omitempty"` - ECH *OutboundECHOptions `json:"ech,omitempty"` - UTLS *OutboundUTLSOptions `json:"utls,omitempty"` - Reality *OutboundRealityOptions `json:"reality,omitempty"` + Enabled bool `json:"enabled,omitempty"` + Engine string `json:"engine,omitempty" enum:"go,apple,windows"` + DisableSNI bool `json:"disable_sni,omitempty"` + ServerName string `json:"server_name,omitempty"` + Insecure bool `json:"insecure,omitempty"` + ALPN badoption.Listable[string] `json:"alpn,omitempty" examples:"http/1.1,h2,h3"` + MinVersion string `json:"min_version,omitempty" enum:"1.0,1.1,1.2,1.3"` + MaxVersion string `json:"max_version,omitempty" enum:"1.0,1.1,1.2,1.3"` + CipherSuites LegacyListable[string] `json:"cipher_suites,omitempty"` + CurvePreferences LegacyListable[CurvePreference] `json:"curve_preferences,omitempty"` + Certificate badoption.Listable[string] `json:"certificate,omitempty"` + CertificatePath string `json:"certificate_path,omitempty"` + CertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"certificate_public_key_sha256,omitempty"` + ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"` + ClientCertificatePath string `json:"client_certificate_path,omitempty"` + ClientKey badoption.Listable[string] `json:"client_key,omitempty"` + ClientKeyPath string `json:"client_key_path,omitempty"` + Fragment bool `json:"fragment,omitempty"` + FragmentFallbackDelay badoption.Duration `json:"fragment_fallback_delay,omitempty"` + RecordFragment bool `json:"record_fragment,omitempty"` + Spoof string `json:"spoof,omitempty"` + SpoofMethod string `json:"spoof_method,omitempty" enum:"wrong-sequence,wrong-checksum,wrong-ack,wrong-md5,wrong-timestamp"` + KernelTx bool `json:"kernel_tx,omitempty"` + KernelRx bool `json:"kernel_rx,omitempty"` + HandshakeTimeout badoption.Duration `json:"handshake_timeout,omitempty"` + ECH *OutboundECHOptions `json:"ech,omitempty"` + UTLS *OutboundUTLSOptions `json:"utls,omitempty"` + Reality *OutboundRealityOptions `json:"reality,omitempty"` } type OutboundTLSOptionsContainer struct { diff --git a/option/types.go b/option/types.go index 32ac6ab06..db549fb3f 100644 --- a/option/types.go +++ b/option/types.go @@ -1,7 +1,9 @@ package option import ( + "context" "maps" + "reflect" "slices" "strings" @@ -10,11 +12,26 @@ import ( E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/json" + "github.com/sagernet/sing/common/json/badoption" N "github.com/sagernet/sing/common/network" mDNS "github.com/miekg/dns" ) +type LegacyListable[T any] []T + +func (l *LegacyListable[T]) UnmarshalJSONContext(ctx context.Context, content []byte) error { + return (*badoption.Listable[T])(l).UnmarshalJSONContext(ctx, content) +} + +func (l LegacyListable[T]) DescribeSchema(builder schema.Builder) (*schema.Node, error) { + elementNode, err := builder.Describe(reflect.TypeFor[T]()) + if err != nil { + return nil, err + } + return &schema.Node{Type: "array", Items: elementNode}, nil +} + type NetworkList string func (v *NetworkList) UnmarshalJSON(content []byte) error { diff --git a/option/wireguard.go b/option/wireguard.go index d25d0d207..8d11d9974 100644 --- a/option/wireguard.go +++ b/option/wireguard.go @@ -23,11 +23,11 @@ type WireGuardEndpointOptions struct { } type WireGuardPeer struct { - Address string `json:"address,omitempty"` - Port uint16 `json:"port,omitempty"` - PublicKey string `json:"public_key,omitempty"` - PreSharedKey string `json:"pre_shared_key,omitempty"` - AllowedIPs badoption.Listable[netip.Prefix] `json:"allowed_ips,omitempty"` - PersistentKeepaliveInterval uint16 `json:"persistent_keepalive_interval,omitempty"` - Reserved []uint8 `json:"reserved,omitempty"` + Address string `json:"address,omitempty"` + Port uint16 `json:"port,omitempty"` + PublicKey string `json:"public_key,omitempty"` + PreSharedKey string `json:"pre_shared_key,omitempty"` + AllowedIPs LegacyListable[netip.Prefix] `json:"allowed_ips,omitempty"` + PersistentKeepaliveInterval uint16 `json:"persistent_keepalive_interval,omitempty"` + Reserved []uint8 `json:"reserved,omitempty"` }