Commit Graph

2795 Commits

Author SHA1 Message Date
MHSanaei 8f556fe2db fix(clients): centre the online dot inside the Online tag (#5238)
The .online-dot uses vertical-align: middle, which in inline layout
aligns to baseline + half x-height — visibly off-centre inside the Ant
Tag's line box. Add a .dot-tag utility (inline-flex, align-items:
center) and apply it to the Online tag so the dot and label share one
centred axis. Other dot usages (Nodes page Space, card heads, stat
rows) already sit in flex containers and are unaffected.
2026-06-13 01:19:19 +02:00
MHSanaei b770287995 fix(sub): stop appending the node name to subscription remarks (#5231)
The #5035 change tagged node-hosted entries with the node name to
disambiguate multi-node subscriptions, but the node name is
panel-internal and leaked into the profile names end users see in
their client apps. Drop the suffix entirely — remarks are the
admin-set inbound remark again.
2026-06-12 22:35:41 +02:00
MHSanaei 3c68b039f6 fix(sub): deliver vision flow for VLESS+XHTTP+REALITY in share links and Clash (#5232)
The vlessenc fix (#5185) enabled flow on XHTTP only in the security=none
branch of genVlessLink, and the Clash builder still gated flow on
network==tcp. With XHTTP+REALITY+vlessenc the panel accepts and stores
the flow (inboundCanEnableTlsFlow passes), but subscriptions dropped it,
so clients received configs without xtls-rprx-vision.

Add vlessFlowAllowed mirroring inboundCanEnableTlsFlow — tcp with
tls/reality, or xhttp with vlessenc regardless of security layer — and
use it in both the vless:// link generator and the Clash proxy builder.
2026-06-12 22:25:04 +02:00
MHSanaei c200e248f7 fix(script): report per-file geo update status and skip restart when nothing changed
Updating geo files printed raw curl progress meters showing 0 bytes when
files were already current (curl -z conditional download), claimed success
unconditionally, and restarted xray even when nothing was downloaded —
confusing enough to be reported as a bug (#5230).

Now each file reports updated / already up to date / download failed,
failures no longer print a success message, and the restart (which drops
live connections) only happens when a file actually changed. Same for the
non-interactive 'x-ui update-all-geofiles' command.
2026-06-12 22:18:42 +02:00
MHSanaei b5ef412b8d v3.3.1 v3.3.1 2026-06-12 20:39:13 +02:00
MHSanaei 41cb0b8ae7 fix(inbounds): show remark first, else inbound tag, in client labels
Revert formatInboundLabel to the pre-#5151 behavior: display the inbound
remark when set, otherwise the inbound tag, instead of "tag (remark)".
Affects the Attach clients / Attached inbounds views and client lists.
Routing keeps its own tag (remark) formatting.
2026-06-12 20:37:37 +02:00
MHSanaei cd46730bb9 Bump Go indirect deps; update frontend lock
Bump several Go indirect dependencies (golang.org/x/exp, golang.org/x/tools, google.golang.org/genproto) and update go.sum accordingly. Regenerate frontend/package-lock.json to record updated npm package versions (including Ant Design and related rc-component packages and other transitive updates).
2026-06-12 20:16:06 +02:00
MHSanaei 4eab37b66c feat(clients): restore reset traffic button in edit client form 2026-06-12 20:15:31 +02:00
MHSanaei 08bc481ae3 refactor(settings): reorganize subscription settings into clearer tabs
- Split the Happ and Clash/Mihomo routing sections out of Information into
  their own dedicated tabs.
- Extract the profile/branding fields (title, support URL, profile page,
  announcement, theme dir) out of the mislabeled "Subscription Title"
  divider into a new Profile tab.
- Move the Update Interval setting into Information and drop the
  single-field Intervals tab.
- Add the "profile" tab label across all locales.
2026-06-12 19:41:02 +02:00
MHSanaei 0f7da02a07 style(inbounds): show total up/down with directional arrows
Replace the ambiguous swap icon on the total traffic statistic with
explicit up/down arrows next to each value.
2026-06-12 19:19:42 +02:00
MHSanaei 0c73862bbe fix(clients): invalidate Xray config cache after client mutations
Client add/update/remove also rewrite settings.clients on each attached
inbound, so the Xray config query could go stale. Invalidate it alongside
the clients and inbounds buckets.
2026-06-12 19:19:42 +02:00
MHSanaei c7a0188772 feat(settings): schedule picker, toggle placement, sub-theme docs link
- Replace the Telegram "Notification Time" free-text field with a guided
  cron builder: @every + number + unit (s/m/h), the @hourly/@daily/@weekly/
  @monthly macros, and a Custom option that seeds a valid 6-field crontab
  (cron runs with seconds enabled) as an escape hatch.
- Move "Restart Xray After Auto Disable" from the External Traffic tab to
  Panel Settings, where it belongs.
- Add a "Template guide" link to the Sub Theme Directory setting pointing at
  docs/custom-subscription-templates.md.
- Localize all new strings across every locale.
2026-06-12 19:19:31 +02:00
iYuan 90e6217749 fix(inbound): preserve custom share strategy on edit (#5225) 2026-06-12 18:38:01 +02:00
MHSanaei 6e20588236 style(ui): enlarge row action icons and rebalance clients table widths
Bump row action icons to 18px across the clients, inbounds, groups and
nodes tables for better visibility.

In the clients table, cap the Client column at 220px and give Duration a
fixed width so the Traffic column becomes the flexible one that absorbs
the remaining horizontal space instead of Client growing oversized.
2026-06-12 18:25:27 +02:00
MHSanaei 5eec178483 feat(mtproto): route Telegram egress through Xray routing rules
Add a per-inbound "Route through Xray" toggle (off by default) plus an
optional outbound picker on MTProto inbounds. mtg only supports a SOCKS5
upstream, so when enabled the panel injects a loopback SOCKS bridge into
the generated Xray config — tagged with the inbound's own tag — and mtg
dials Telegram through it via a [network] proxies upstream. The router
then governs Telegram egress: matchable in the Routing tab, or forced to a
chosen outbound/balancer via the picker.

- mtproto: Instance carries RouteThroughXray + XrayRoutePort (in the
  fingerprint); InstanceFromInbound parses them; renderConfig emits the
  socks5 [network] upstream; freeLocalPort exported as FreeLocalPort.
- xray.go: injectMtprotoEgress appends the loopback SOCKS bridge and
  prepends an optional inboundTag->outbound/balancer rule, hot-appliable
  like injectPanelEgress.
- inbound.go: backend-owned egress port persisted in settings, allocated
  once and carried across edits (stored value wins); stripped with the
  inert outboundTag when routing is off; allocation failure fails the save;
  routed add/update/del force a config regen.
- mtproto_job: skip folding mtg metrics for routed inbounds (the bridge,
  carrying the inbound tag, is metered by xray_traffic_job) to avoid
  double-counting.
- frontend: toggle + outbound/balancer Select (useOutboundTags) on the
  MTProto form; i18n keys for all locales.
2026-06-12 17:58:45 +02:00
MHSanaei 5716ae5987 feat(outbound): batched connection tester with direct timed HTTP probes
Replace the per-outbound burstObservatory polling (one temp xray spawn +
up to 15s of /debug/vars polling per outbound, serialised) with one
shared temp xray instance per batch: every tested outbound gets its own
loopback SOCKS inbound plus an inboundTag->outboundTag routing rule, and
the panel times a real HTTP request through each one in parallel. The
probe returns as soon as the response lands and records the HTTP status
plus an httptrace breakdown (proxy connect / TLS via outbound / first
byte) shown in the result popover.

New POST /panel/api/xray/testOutbounds endpoint (array in, results in
input order, max 50); the legacy /testOutbound endpoint now delegates to
the same engine. Test All chunks HTTP probes 16 per request, and a batch
whose shared process never comes up (one structurally-broken outbound
poisons the config) retries each item in an isolated instance so the
broken outbound reports xray's real error while the rest still test.
2026-06-12 16:55:53 +02:00
MHSanaei 85983eec1a refactor(groups): restyle traffic summary into upload/download + usage cards
Split the group traffic summary into two inbound-style cards: a "Total
upload / download" card with up/down arrow icons and a "Total Usage" card
with the pie icon. Add the totalUpDown label across all locales.
2026-06-12 16:22:30 +02:00
MHSanaei 5af02265ec fix(inbound): remove stale mkcp-legacy finalmask when switching away from mKCP
Switching the transport to mKCP auto-seeds a mkcp-legacy entry into
finalmask.udp, but switching back to another transport only dropped the
kcpSettings blob and left the mask behind. It survived downstream pruning
(finalmask.udp was non-empty) and bled into every client share link.

Strip auto-seeded mkcp-legacy entries from finalmask.udp whenever the
network changes away from kcp, leaving user-authored masks intact.

Fixes #5221
2026-06-12 15:35:41 +02:00
MHSanaei 1c5cb84492 feat(groups): show upload/download breakdown in group traffic
Add per-group up/down to GroupSummary (backend + schema), surface them
as Upload/Download columns in the groups table, and fold upload/download
into the Total traffic summary card. Rename the group "Clients in group"
column to just "Clients" across all locales.
2026-06-12 15:30:41 +02:00
MHSanaei 7c698c4bcf feat(inbound): support abstract unix sockets (@ prefix) in Address field
Accept the @-prefixed abstract socket form (e.g. @xray/in.sock) for an
inbound listen address, not just path-based sockets. The form now allows
Port 0 for both, and the Address help text documents the @ form across
all locales. The backend already treated both prefixes as unix sockets.
@
2026-06-12 14:34:02 +02:00
MHSanaei 80e168787e fix(xray): confine log.access/error to the panel log folder
An authenticated admin could set xrayTemplateConfig.log.access/error to an
arbitrary path (via the raw Xray editor or a wholesale DB import), making the
supervised Xray process write its log there — an arbitrary file write as the
Xray user (root in many deployments). resolveXrayLogPaths now reduces any log
path to its base filename under config.GetLogFolder(), so absolute paths and
".." traversal can no longer escape the log folder; "" and "none" still
disable logging.
2026-06-12 14:25:06 +02:00
MHSanaei 3af1afc53b fix(inbound): avoid UNIQUE email constraint when importing inbounds that share clients
Importing a second inbound whose clients overlap an already-imported inbound
failed with "UNIQUE constraint failed: client_traffics.email". The import path
carries exported ClientStats, and tx.Save(inbound) cascaded that has-many
association as INSERTs whose ON CONFLICT targets only the primary key, so a
shared email (already owning a row from the first import) tripped the global
unique constraint.

Omit the ClientStats association on save and insert the carried stats ourselves
with the same OnConflict{email, DoNothing} guard AddClientStat already uses:
new clients keep their imported counters, shared emails reuse the existing row.
Then run an idempotent AddClientStat pass over all clients so any client present
in settings but missing from the stats payload still gets a traffic row (else it
would escape quota/expiry accounting), and propagate insert errors so the tx
rolls back instead of committing a partial state.
2026-06-12 13:00:04 +02:00
MHSanaei 0cefadd166 feat(ui): use CodeMirror editor for Import Inbound and Inbound JSON 2026-06-12 12:38:18 +02:00
Rouzbeh† 0766e16684 feat: implement inbound XMUX form fields (#5211)
* feat: implement inbound XMUX form fields

* fix: replace any cast to satisfy eslint

* test: update xhttp form snapshot for XMUX

* fix(inbound): persist xmux on save so the XMUX form actually round-trips

The inbound wire normalizer unconditionally deleted xhttpSettings.xmux,
so the new inbound XMUX form was stripped on save and never reached the
stored config — the subscription extra blob (buildXhttpExtra) could
never see it. Gate the deletion on the enableXmux toggle, mirroring the
outbound adapter, and add regression tests for both on/off cases.

* fix(xmux): enforce xray-core's maxConnections/maxConcurrency exclusivity

xray-core's XmuxConfig rejects a config that sets both maxConnections
and maxConcurrency. The panel pre-fills maxConcurrency ('16-32') whenever
XMUX is enabled, so an explicit maxConnections would always collide and
make xray refuse the config. Mirror core's semantics in the wire
normalizer: when maxConnections is set (>0, an explicit opt-in since it
defaults to 0), drop the leftover default maxConcurrency. Applies to both
inbound and outbound xhttp.

---------

Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
2026-06-12 12:31:13 +02:00
ssrlive 63a6d40457 Update ExecReload command in x-ui.service.debian (#5219)
* Update ExecReload command in x-ui.service.debian

* fix(systemd): use absolute path in ExecReload for arch and rhel units

systemd requires absolute executable paths; kill -USR1 $MAINPID fails
with 'Executable path is not absolute'. Matches the debian unit fix.

---------

Co-authored-by: MHSanaei <ho3ein.sanaei@gmail.com>
2026-06-12 12:09:48 +02:00
MHSanaei f1a4286e2f feat(sub): per-inbound sort order for subscription links
Add a subSortIndex field to inbounds that controls the order of links
in subscription output only: the raw sub body, the HTML sub page, and
the JSON/Clash formats (all served from the same query). Lower values
come first; ties keep id order. The panel inbound list is unaffected.

The value is editable in the inbound form next to the share-address
fields, propagates to nodes via wireInbound, and follows the usual
node-sync rules (copied on import, mirrored while not dirty, never a
structural change).

Rescoped from #5214 by @Ponywka.
2026-06-12 12:03:22 +02:00
MHSanaei 7ae3ea66d1 feat(ui): improve client form modal UX
- Rename tabs: "Basic" → "Basics", "Config" → "Credentials"
- Move reverseTag field from Credentials tab to Basics tab
- Move IP log button inline with limitIp field (tooltip button, edit mode only)
- Hide random email button when editing an existing client
- Add tooltips to totalGB and limitIp fields with descriptive hints
- Rename labels: "Total Sent/Received (GB)" → "Traffic Limit (GB)", "Duration" → "Duration (days)"
- Add renewDays translation key for auto-renew label with unit hint
- Remove redundant filterOption and width style from AutoComplete group selectors
- Update all 15 locale files with new and renamed translation keys
2026-06-12 10:38:26 +02:00
MHSanaei 253063b785 feat: filter inbounds and clients by node (#4997)
Multi-node panels had no way to narrow the inbounds or clients lists to
a single node. Add a node filter to both pages:

- Inbounds: a toolbar select (All / Local / each node) that filters the
  list client-side; shown only when the panel has nodes or node-attached
  inbounds.
- Clients: a Nodes multi-select in the filter drawer. Node selections
  are mapped onto inbound IDs client-side and fed through the existing
  inbound CSV paging parameter, so the paging backend is untouched; an
  impossible id (-1) is sent when no inbound matches so the filter
  yields an honest empty result. InboundOption now carries nodeId to
  make the mapping possible.

The local panel is selectable via a 0 sentinel (inbounds without a
nodeId). New i18n keys in all 13 locales.
2026-06-12 09:33:35 +02:00
MHSanaei d04cb10971 feat(wireguard): per-peer comments for identifying devices (#5168)
WG peers were only identifiable by their keys. Add an optional panel-side
comment per peer: editable in the inbound form (echoed next to "Peer N"
in the section header), stored in the settings JSON alongside the
panel-only privateKey (xray-core ignores unknown peer fields), and
appended to the share link / .conf remark so the device is identifiable
in client apps too.
2026-06-12 09:10:57 +02:00
MHSanaei d1a13844b2 feat(api): include consumed traffic in the client-get response (#4973)
GET /panel/api/clients/get/:email returned the quota (totalGB) but not
the bytes the client has actually used, forcing API consumers to scrape
it elsewhere. Add a sibling "usedTraffic" field (up+down, including the
cross-node global overlay) next to "client" and "inboundIds".
2026-06-12 09:06:35 +02:00
MHSanaei bade1fcef6 feat(ui): allow custom fragment packets ranges, not just presets (#5075)
The fragment "packets" field was a locked dropdown (tlshello / 1-3 / 1-5)
in both the finalmask TCP-mask form and the Freedom outbound form, while
xray-core accepts any "n-m" packet range. Replace both with an
AutoComplete that keeps the presets as suggestions and validates free
input as "tlshello" or a numeric range.
2026-06-12 09:04:17 +02:00
MHSanaei 0e0e41197f fix(settings): normalize tgCpu on load so a bad value can't block saving (#5091)
The settings page validates the whole AllSetting object before saving, so a
tgCpu value that isn't an integer in 0-100 (left over from an older or corrupt
setting) failed validation with "tgCpu: Invalid input" and blocked saving every
other setting too. Clamp/round tgCpu to a valid integer in the model
constructor, defaulting to 80 when it isn't a finite number.
2026-06-12 03:17:32 +02:00
MHSanaei 5c29851be1 fix(nodes): "Invalid input" when saving a node with inbound sync mode "all"
NodeFormSchema required inboundTags, but the inboundTags Form.Item is only
mounted when inboundSyncMode is "selected" - antd onFinish omits unmounted
fields, so saving with the default "all" mode failed schema validation with
Zod generic "Invalid input" (regression from #5178; same class as the
earlier pinnedCertSha256 fix).

Also tolerate null inboundTags (Go nil slice) for nodes saved before #5178,
both in the form schema and NodeRecordSchema, and normalize edit-mode values.
2026-06-12 02:29:46 +02:00
MHSanaei 60da6bed15 fix(xhttp): stop injecting scMaxEachPostBytes/scMinPostsIntervalMs defaults (#5141)
The panel seeded xhttp configs with scMaxEachPostBytes=1000000 and
scMinPostsIntervalMs=30 — xray-core''s own defaults — and emitted them
into every generated config and share link. The literal
scMinPostsIntervalMs=30 is a stable DPI fingerprint that Russia''s TSPU
keys on to block connections on mobile networks.

New configs no longer seed these values (empty schema/template defaults,
so xray-core applies its internal defaults). For configs already stored
with the old defaults, the link/subscription builders now drop values
equal to xray-core''s defaults instead of advertising them — covering
panel share links, the raw subscription, and the JSON subscription
without requiring every inbound to be re-saved. Non-default values the
user set deliberately are still emitted.
2026-06-12 01:50:37 +02:00
MHSanaei 7e87b7dc60 i18n: point API token hint at the Authentication page in all locales
The remote panel's API token moved from Settings to the Authentication
page; update the node form hint accordingly.
2026-06-12 01:32:00 +02:00
MHSanaei dbee150b33 fix(script): SSL management fixes (#4994, #5010, #5070)
- Issue acme.sh HTTP-01 over IPv4 unless the host has no global IPv4
  address: the hardcoded --listen-v6 started a v6-only standalone
  listener, so validation of a domain whose A record points at this
  host always failed (#4994).
- Add a custom cert/key path option to the "Set Cert paths" menu so
  certificates living outside /root/cert (e.g. certbot under
  /etc/letsencrypt) can be wired to the panel from the CLI (#5010).
- Derive the displayed Access URL from the certificate's actual SAN
  list instead of the cert folder name, list the other covered names,
  and show the panel's custom-path certificate in "Show Existing
  Domains" (#5070). Also silence find when /root/cert doesn't exist.
2026-06-12 01:22:30 +02:00
MHSanaei 1a525b4cb4 fix(client): apply per-field client edits to every inbound of the email (#5039)
applyClientFieldByEmail patched only the first inbound that the
client_traffics row pointed at. For a multi-inbound client the sibling
inbounds kept the old expiryTime/totalGB/limitIp in their settings JSON,
and the next SyncInbound over a stale sibling reverted the edit in the
normalized records — the Telegram bot's expiry change appeared to apply
and then sprang back. Patch the field on every inbound linked to the
email, falling back to the legacy single-inbound lookup for clients that
were never normalized.
2026-06-12 01:22:15 +02:00
MHSanaei b062cb5a14 fix(sub): tag node-hosted entries with the node name in remarks (#5035)
An inbound pushed to nodes keeps the same remark on every copy, so a
multi-node subscription (and the panel's per-client link view) listed
several identically-named entries differing only by address. Append the
node name to the remark of node-hosted inbounds unless the admin already
included it.
2026-06-12 01:22:15 +02:00
MHSanaei a27d57b2ff fix(ui): keep dropdown action menus inside the viewport (#5133)
The inbound/client context menus hold a dozen items; when antd flips a
tall menu upward near the screen edge it overflowed the top of the
viewport, hiding the first entries. Cap the overlay height and scroll.
2026-06-12 01:21:54 +02:00
MHSanaei 10a0c9131c fix(hysteria): clamp udpIdleTimeout to xray-core's accepted 2-600s range (#5117)
The schema and form inputs allowed any value >= 1, but xray-core rejects
UdpIdleTimeout outside 2-600 seconds at startup, so an out-of-range value
silently killed the whole config.
2026-06-12 01:21:54 +02:00
MHSanaei a5e5640804 fix(inbound): explain how to unlock fallbacks on the inbound form (#5014)
The fallbacks card only renders for VLESS/Trojan over RAW with TLS or
Reality security, and a new inbound starts at security=none — so the Add
Inbound page looked like it had lost fallback support entirely. Show an
inline hint in that state pointing at the Security tab.
2026-06-12 01:21:38 +02:00
MHSanaei 0711d3077b chore: pin generated files to LF to avoid phantom CRLF diffs on Windows 2026-06-11 23:41:01 +02:00
MHSanaei 8578b229ce feat(settings): allow a balancer as the panel traffic outbound
The panel egress is injected as a routing rule, so a routing balancer is
a valid target for it (unlike the geodata download, which dials a forced
outbound tag and bypasses the router). Surface routing balancers in the
panel outbound picker as a separate group, and emit balancerTag instead
of outboundTag in the injected egress rule when the configured tag names
a balancer, so the panel's own traffic load-balances across its members.
2026-06-11 23:32:58 +02:00
MHSanaei c47a905ad2 fix(inbound): offer node share-address strategy only when a node exists
The `node` share-address strategy resolves to an address only when the
inbound can live on a node; for a local inbound it is always empty and
behaves like `listen`. Drop the `node` option from the picker unless an
enabled, node-eligible node exists, and coerce the value to `listen`
otherwise so the Select never shows an option that does nothing.
2026-06-11 23:32:47 +02:00
MHSanaei 825778144c fix(outbound): widen probe timeout and surface failure reason in outbound test (#5152)
The v3 outbound test spins up a temp xray that probes the outbound via
burstObservatory. Two regressions made it report "Failed" for healthy
outbounds on high-latency / tunnel-routed boxes (e.g. default route over
an OpenVPN tun device to a remote proxy), even though client traffic over
the same outbound works:

- Each probe disables keep-alive, so every attempt is a cold round-trip
  (redial + re-handshake). The 5s per-probe timeout was too tight for such
  paths and every probe timed out. Restore the ~10s budget the pre-v3
  SOCKS-based test gave a cold connection (timeout 5s -> 10s) and widen the
  poll window 12s -> 15s so one full probe can complete and surface alive.

- The temp config set log error to "none", discarding the real failure
  reason, so "Failed" was undiagnosable. Route error logs to stderr ("")
  like the production template does, so the probe error (DNS lookup
  failure, connection refused, deadline exceeded, TLS error, ...) is
  captured into the panel/Xray log, and point the operator there in the
  generic timeout messages.
2026-06-11 22:49:22 +02:00
MHSanaei 1b0dbf8e6d fix(sub): deduplicate settings.clients entries per inbound in subscription output (#5134)
Multi-node sync/import drift can leave the same client twice inside an
inbound's legacy settings.clients JSON while the normalized
client_inbounds table stays clean (SyncInbound dedupes the rows it
writes but never rewrites the JSON). All three subscription builders
iterated that JSON verbatim, so every duplicate entry became a
duplicate profile in the raw, Clash, and JSON output.

Filter and dedupe by email in one shared helper (link generation keys
purely on inbound + email, so same-email entries are pure duplicates
and dropping them is lossless). The clash/json services' own
inboundService copies became unused and are removed.
2026-06-11 22:19:14 +02:00
MHSanaei 09a887f95c fix(warp): prefer IPv4 with v6 fallback and userspace TUN in generated WireGuard outbounds (#5205)
The generated WARP outbound used domainStrategy ForceIP, which may pick
the AAAA record for engage.cloudflareclient.com; on a host with
half-configured IPv6 the handshake then blackholes with nothing in the
logs. ForceIPv4v6 prefers IPv4 and still falls back to IPv6 on
v6-only hosts, matching the official WARP client's behavior.

It also set noKernelTun: false, so with root privileges the real
outbound used kernel TUN — a path that needs CAP_NET_ADMIN plus fwmark
routing and fails silently on many VPS setups — while the panel's
connectivity probe always tests with noKernelTun: true. The status
check and real traffic exercised different data paths and could
disagree. Generate WARP and NordVPN outbounds with the userspace TUN
so both follow the path the probe validates.

Only affects newly added/reset outbounds; existing templates keep
their saved settings.
2026-06-11 21:49:45 +02:00
MHSanaei cc65f37164 fix(sub): honor per-inbound share address strategy in subscription output (#5208)
Subscriptions resolved a node-managed inbound's address to the node's
panel address unconditionally, so an inbound bound to a specific public
IP advertised an endpoint clients could not reach. The shareAddrStrategy
field added in #5162 only applied to panel share/QR links by design.

resolveInboundAddress now follows the same order as the panel's link
builder: 'listen' prefers a routable bind, 'custom' prefers shareAddr,
and the default 'node' keeps the existing node-first behavior, so output
is unchanged for inbounds that never set the field. Applies to raw,
JSON, and Clash subscriptions, which all resolve through this path.
Help text in all locales updated to drop the 'subscriptions are not
affected' caveat.
2026-06-11 21:31:27 +02:00
MHSanaei 21143a6d72 fix(node-sync): keep node baseline while a sibling inbound still reports the email (#5202)
The orphan sweeps in setRemoteTrafficLocked deleted the (node, email)
baseline row unconditionally whenever an email was missing from one
inbound's snapshot stats — even though baselines are keyed per node, not
per inbound. For a client attached to two inbounds of the same node whose
stats the node reports under only one of them, the sweep for the other
inbound deleted the baseline at the end of every sync cycle. Depending on
inbound order, the baseline written earlier in the same transaction was
wiped each time, so the next cycle computed delta against a missing
baseline (zero) and the client's traffic froze permanently.

Scope both sweeps to the union of emails across the whole snapshot: a
baseline is only dropped when the email left the node entirely.
2026-06-11 21:20:38 +02:00
MHSanaei 1508666e52 fix: DNS server edit modal showing defaults instead of saved values (#5155)
The DNS server table columns were memoized with only [t] as deps, so
they permanently captured the first render's openEditServer callback,
which closed over the initial (null) dns settings. Clicking Edit then
resolved the server to null and the modal fell back to default values.

Stabilize openEditServer/deleteServer (and the fakedns equivalents)
with useCallback and include them in the column memo deps so the
columns refresh whenever the servers list changes.
2026-06-11 20:58:23 +02:00