Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/core/hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async def _prepare_subscription_inbound_data(
transport_config=TCPTransportConfig(path="", host=[]),
mux_settings=None,
wireguard_public_key=inbound_config.get("public_key", ""),
wireguard_pre_shared_key=inbound_config.get("pre_shared_key", None),
wireguard_pre_shared_key=inbound_config.get("pre_shared_key") or "",
wireguard_local_address=inbound_config.get("address", []) or [],
wireguard_allowed_ips=allowed_ips,
wireguard_keepalive=keepalive,
Expand Down
25 changes: 24 additions & 1 deletion app/core/xray.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from app.models.core import CoreType
from app.models.protocol import ProxyProtocol
from app.utils.crypto import get_cert_SANs, get_x25519_public_key
from app.utils.crypto import get_cert_SANs, get_wireguard_public_key, get_x25519_public_key


def _protocols_from_inbounds_by_tag(inbounds_by_tag: dict[str, dict]) -> frozenset[ProxyProtocol]:
Expand Down Expand Up @@ -419,8 +419,31 @@ def _resolve_inbounds(self):
self._read_inbound(inbound)
self._protocols = _protocols_from_inbounds_by_tag(self._inbounds_by_tag)

def _read_wireguard_inbound(self, inbound: dict):
"""Register a WireGuard-in-Xray inbound so its tag appears in /api/inbounds."""
wg = inbound.get("settings", {})
secret_key = wg.get("secretKey", "")
try:
public_key = get_wireguard_public_key(secret_key) if secret_key else ""
except Exception:
public_key = ""
settings = self._create_base_settings(inbound)
settings["listen_port"] = inbound.get("port")
settings["public_key"] = public_key
settings["address"] = wg.get("address", [])
settings["mtu"] = wg.get("mtu", 1420)
settings["network"] = "udp"
tag = inbound["tag"]
if tag not in self._inbounds:
self._inbounds.append(tag)
self._inbounds_by_tag[tag] = settings

def _read_inbound(self, inbound: dict):
"""Read an inbound and its settings."""
if inbound["protocol"] == "wireguard":
self._read_wireguard_inbound(inbound)
return

if inbound["protocol"] not in ("vmess", "vless", "trojan", "shadowsocks", "hysteria"):
return

Expand Down
6 changes: 5 additions & 1 deletion app/jobs/record_usages.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ def _process_users_stats_response(stats_response):
Process stats response (CPU-bound operation) - runs in thread pool.
Pure function designed for thread-safe execution.
Returns tuple: (validated_params, invalid_uids) for logging outside thread.

Every inbound (including WireGuard) reports stats keyed by the user's
email, which the panel sets to the plain `{id}`, so no translation is
needed here.
"""
params = defaultdict(int)
for stat in filter(attrgetter("value"), stats_response.stats):
Expand All @@ -498,7 +502,7 @@ def _process_users_stats_response(stats_response):
for uid, value in params.items():
try:
validated_params.append({"uid": int(uid), "value": value})
except ValueError, TypeError:
except (ValueError, TypeError):
invalid_uids.append(uid)

return validated_params, invalid_uids
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1237,9 +1237,10 @@ export function XrayInboundsSection({ headerAddPulse, headerAddEpoch }: XrayInbo
let tag = watchedProtocol
let network = watchedTransport
if (watchedProtocol === 'shadowsocks') network = watchedShadowsocksNetwork
if (isWireguardInboundProtocol(watchedProtocol)) network = 'udp'

if (network) tag += `${tagSeparator}${network}`
if (watchedSecurity && watchedSecurity !== 'none') tag += `${tagSeparator}${watchedSecurity}`
if (!isWireguardInboundProtocol(watchedProtocol) && watchedSecurity && watchedSecurity !== 'none') tag += `${tagSeparator}${watchedSecurity}`
if (watchedPort) tag += `${tagSeparator}${watchedPort}`

tag = tag.toUpperCase()
Expand Down Expand Up @@ -1625,7 +1626,10 @@ export function XrayInboundsSection({ headerAddPulse, headerAddEpoch }: XrayInbo
setDuplicateTagError(tagValue)
return
}
if (inbound.protocol !== 'unmanaged' && 'transport' in inbound && 'security' in inbound) {
if (isWireguardInboundProtocol(inbound.protocol)) {
const ok = await form.trigger(['protocol', 'tag', 'port', 'wgSecretKey'], { shouldFocus: true })
if (!ok) return
} else if (inbound.protocol !== 'unmanaged' && 'transport' in inbound && 'security' in inbound) {
const fields = ['protocol', 'tag', 'port', ...(form.getValues('security') === 'reality' ? realityInboundZodTriggerFieldNames() : [])]
const ok = await form.trigger(fields, { shouldFocus: true })
if (!ok) return
Expand All @@ -1635,9 +1639,6 @@ export function XrayInboundsSection({ headerAddPulse, headerAddEpoch }: XrayInbo
} else if (inbound.protocol === 'tun') {
const ok = await form.trigger(['protocol', 'tag', 'tunName', 'tunMtu'], { shouldFocus: true })
if (!ok) return
} else if (inbound.protocol === 'wireguard') {
const ok = await form.trigger(['protocol', 'tag', 'port', 'wgSecretKey'], { shouldFocus: true })
if (!ok) return
}
if (!validateWireguardInboundForCommit(inbound)) return
let nextInbound: Inbound = inbound
Expand Down Expand Up @@ -2501,7 +2502,7 @@ export function XrayInboundsSection({ headerAddPulse, headerAddEpoch }: XrayInbo
<p className="text-muted-foreground text-sm">{t('coreEditor.inbound.unmanagedHint', { defaultValue: 'This inbound is managed as raw JSON in Advanced.' })}</p>
)}

{inbound && inbound.protocol !== 'unmanaged' && 'transport' in inbound && 'security' in inbound && (
{inbound && inbound.protocol !== 'unmanaged' && !isWireguardInboundProtocol(inbound.protocol) && 'transport' in inbound && 'security' in inbound && (
<Form {...form}>
<form className="flex flex-col gap-4 pb-6" onSubmit={e => e.preventDefault()}>
<div className="grid gap-4 sm:grid-cols-2">
Expand Down Expand Up @@ -4643,7 +4644,7 @@ export function XrayInboundsSection({ headerAddPulse, headerAddEpoch }: XrayInbo
</Form>
)}

{inbound && inbound.protocol !== 'unmanaged' && !('transport' in inbound) && !isTunnelInboundProtocol(inbound.protocol) && (
{inbound && inbound.protocol !== 'unmanaged' && (isWireguardInboundProtocol(inbound.protocol) || !('transport' in inbound)) && !isTunnelInboundProtocol(inbound.protocol) && (
<Form {...form}>
<form className="space-y-4" onSubmit={e => e.preventDefault()}>
<div className="grid gap-3 sm:grid-cols-2">
Expand Down
2 changes: 2 additions & 0 deletions dashboard/src/features/core-editor/kit/sanitize-inbound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ function sanitizeWireguardEmptyAddress(inbound: Inbound): Inbound {
if (Array.isArray(draft.address) && draft.address.length === 0) {
delete draft.address
}
delete draft.transport
delete draft.security
return draft as unknown as Inbound
}

Expand Down