feat(xray): Add Xray 26.7.11 FinalMask xmc settings to hosts/inbound/subscription (UI too). Add sessionID compatibility + add 2 new fields: sessionIDTable + sessionIDLength (and the corresponding UI). - #671
Conversation
fix: detect admins.id type at runtime in api_keys migration
WalkthroughXHTTP session ID table and length settings are added across backend models, Xray transport serialization, dashboard forms, host editing, inbound editor controls, localization, and regression tests. TCP final-mask configuration also gains an XMC variant with dashboard editing support. ChangesXHTTP Session Configuration
XMC TCP Final Mask
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant HostEditor
participant HostForm
participant XHTTPTransport
participant XrayConfig
HostEditor->>HostForm: set session ID table and length
HostForm->>XHTTPTransport: submit validated XHTTP settings
XHTTPTransport->>XrayConfig: emit sessionID fields
XrayConfig->>XrayConfig: parse sessionID keys or legacy fallbacks
Possibly related PRs
Suggested labels: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
First this version of xray is still pre release and there is no warranty this be the same in stable version. |
…se core versions - Remove migrate_core_xhttp_session_keys_if_sole_node() and its call site in update_node_status(): the panel was silently rewriting an admin's stored Xray core JSON (sessionPlacement/sessionKey -> sessionIDPlacement/ sessionIDKey) as soon as any node reported Xray >= 26.6.22, with no confirmation. This is redundant on top of the per-push rename already done in NodeOperation.connect_node (which translates a deep copy at the moment config is sent to a node, based on that node's own version) and the dual-name read fallback in XRayConfig/subscription builders, so removing it costs no functionality while no longer touching admin data behind their back. - update-core-modal.tsx: warn when the selected/entered core version is a pre-release or numerically above the latest stable release, separate from the existing sessionID breaking-change warning.
…nt Xray versions
node-modal.tsx: when selecting a Core Config, fetch the other nodes already
using it (useGetNodes({ core_id })) and show a muted, non-blocking hint if
their reported Xray versions differ — that core is pushed to every node
unmodified except for the handful of fields the panel already translates
per node version, so anything else version-specific can behave differently
across them. Kept as a warning rather than a hard block, consistent with
not forcing changes on the admin's data.
get_xray_version_by_core_id previously picked an unordered .limit(1) row when a core config is shared by multiple nodes, so the core-editor's version-aware gating (e.g. Session ID Table/Length visibility) could pin to an arbitrary sibling node's version instead of the one actually being configured. Now it picks the highest reported version among all nodes on that core, so the editor never hides a capability a real node on the core actually supports; the admin is separately warned elsewhere when nodes on a shared core report different versions.
…op redundant block
- Restyle the pre-release-version warning to match the removed
breaking-change warning's amber styling instead of blue, so there's one
consistent look instead of two stacked warnings when both applied.
- Drop the breaking-change warning's own UI block; the version-threshold
check it was built on (isBreaking) stays, since the backend still
requires `confirm: true` when actually crossing the sessionID-rename
boundary — only the now-redundant dedicated banner is gone.
- Fix an unclear ru translation ("боевых нодах" → "продакшен-нодах").
|
@M03ED
Added a non-blocking warning when the selected/entered version is a pre-release (or above current latest stable). It also covers the 26.6.22 sessionID-rename crossing — that used to be its own separate banner, but since practically every version past 26.4.13 is pre-release anyway, showing two stacked warnings for the same underlying situation was redundant, so I folded it into this one. This isn't just caution — it has a real use case. Xray-core's e10347bf (v26.6.22) added SessionIDTable/SessionIDLength, the only way to stop XHTTP from putting a UUID in the request path — which a growing number of CDNs in Russia now filter on (and a lot of people were begging Xray-core's developers to merge that feature). I checked the officially published @pasarguard/xray-config-kit@0.3.4 (what dev actually depends on) directly: it doesn't know these fields exist at all — silently drops them in permissive mode, refuses to compile in strict mode, and its parity data doesn't go past v26.5.3. So today, on upstream, this isn't just untested — it's unreachable through the panel regardless of the node's actual Xray version. That's the concrete reason to track a version this new.
Removed migrate_core_xhttp_session_keys_if_sole_node() entirely — it silently rewrote the admin's stored core config in the DB. The DB is never touched without an explicit admin action now. What's left is a transient, non-persisted rename (rename_xhttp_session_keys in NodeOperation.connect_node) applied only to the copy pushed to a given node, never written back to the DB. Same pattern the codebase already uses for Xray-core's earlier splithttp → xhttp rename (app/subscription/clash.py). Without it, an admin's configured sessionPlacement/sessionKey would silently stop applying once a node crosses 26.6.22. That said, I'm not attached to it — happy to just remove it too if you'd rather the panel not touch the outgoing config at all.
No hard block, but the node editor now warns when a Core Config is shared with nodes reporting a different Xray version. |
checkSessionIdRoomSize() and its three call sites (Hosts form, inbound editor, profile-level persist check) previously skipped validation whenever either sessionIDTable or sessionIDLength was missing, treating it as "nothing to check yet". That's only true in one direction: Xray-core only runs this check when sessionIDTable is set at all (infra/conf/ transport_internet.go gates the whole block on `c.SessionIDTable != ""`), but once a table is set there's no default for sessionIDLength — an unset or invalid length hits the same Build()-time error as a too-small range. A table configured without a length now gets flagged instead of silently saving a config Xray would refuse to start.
|
Is it okay now? Or something needs to be changed/fixed? |
|
this is all extra stuff, all you should add is a extraction from core file and placing them in client configuration (at most adding them to host if it make sense), core should not be dependent on node, node is dependent to core. |
|
okay, got it. Give me some time to adapt that |
cbc3418 to
62cb780
Compare
|
Done. only kept extraction of session_id_table/session_id_length into the client config (+ host override), plus the corresponding frontend UI (host modal fields, core-editor inbound fields) and API types/locales for those two fields. Everything else removed — no version branching in subscriptions, no Core→Node dependency. |
…-bugs # Conflicts: # dashboard/bun.lock # dashboard/package.json # dashboard/src/service/api/index.ts
Adds a direct dependency override so the panel picks up the published 0.3.6 release instead of the beta version pulled in transitively via core-kit.
method, sessionIDPlacement/sessionIDKey and session_id_table were passing through empty strings as real values instead of falling back to defaults like the rest of the xhttp settings already do.
Fix/xhttp session id bugs
|
Well, i guess it's ready.
What was added/changed:
Btw checked xmc finalmask settings in the real case, works wonderful 😊 (Checked XHTTP config with sessionIDKey, sessionIDPlacement, sessionIDTable, sessionIDLength through Yandex CDN, works good) |
|
@ImMohammad20000 Thanks for merging PasarGuard/xray-config-kit#2! Could you please update Core-kit accordingly so I can change dependencies in my PR to actual Pasarguard packages? |
|
@FunLay123 i will do it my self |
ah, okay |
|
@ImMohammad20000 Hey, checking in on this — looks like xray-config-kit is still at 0.3.5 on npm, while the repo is already at 0.3.6. Whenever you get a chance, could you run the publish for it? The same for core-kit on npm (tho core-kit still points at 0.3.5 version of xray-confjg-kit, so it needs to be updated in the repo firstly, then published). I can open a small PR in core-kit myself to bump its xray-config-kit dependency to 0.3.6, if that helps move things along. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/models/host.py (1)
40-40: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCorrect the regex validation patterns.
(:?...)is an optional literal colon, not a non-capturing group, so values such as:tlshelloand:randare accepted. Theapply_topattern is unanchored and can accept invalid strings containingip,ipv4, oripv6.Proposed fix
- packets: str = Field(pattern=r"^(:?tlshello|[\d-]{1,16})$") + packets: str = Field(pattern=r"^(?:tlshello|[\d-]{1,16})$") - type: str = Field(pattern=r"^$|^(:?rand|array|str|base64|hex)$") + type: str = Field(pattern=r"^(?:rand|array|str|base64|hex)?$") - apply_to: str = Field(default="ip", pattern=r"ip|ipv4|ipv6") + apply_to: str = Field(default="ip", pattern=r"^(?:ip|ipv4|ipv6)$")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/models/host.py` at line 40, Correct the regex validation patterns in the model fields: update the packets pattern to use a proper non-capturing group so only tlshello or the numeric range format is accepted without a leading colon, and anchor the apply_to pattern at both ends so only complete valid values (ip, ipv4, or ipv6) are accepted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dashboard/package.json`:
- Line 21: Replace the temporary npm alias in the dashboard package manifest so
`@pasarguard/xray-config-kit` resolves directly to the published official
`@pasarguard` package at version 0.3.6, rather than the `@funlay` package.
In `@dashboard/src/features/hosts/components/finalmask-settings.tsx`:
- Around line 823-824: Mask the XMC password inputs by adding password input
types at both affected sites:
dashboard/src/features/hosts/components/finalmask-settings.tsx lines 823-824 and
dashboard/src/features/core-editor/components/shared/xray-stream-finalmask-editor.tsx
lines 905-906. Update the matching XMC password fields in the surrounding editor
components, preserving their existing form bindings and styling.
---
Outside diff comments:
In `@app/models/host.py`:
- Line 40: Correct the regex validation patterns in the model fields: update the
packets pattern to use a proper non-capturing group so only tlshello or the
numeric range format is accepted without a leading colon, and anchor the
apply_to pattern at both ends so only complete valid values (ip, ipv4, or ipv6)
are accepted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 0705e313-49c6-45c5-b05d-796ab00648d5
⛔ Files ignored due to path filters (1)
dashboard/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (16)
app/core/hosts.pyapp/core/xray.pyapp/models/host.pyapp/models/subscription.pydashboard/package.jsondashboard/public/statics/locales/en.jsondashboard/public/statics/locales/fa.jsondashboard/public/statics/locales/ru.jsondashboard/public/statics/locales/zh.jsondashboard/src/features/core-editor/components/shared/xray-stream-finalmask-editor.tsxdashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsxdashboard/src/features/hosts/components/finalmask-settings.tsxdashboard/src/features/hosts/components/hosts-list.tsxdashboard/src/features/hosts/dialogs/host-modal.tsxdashboard/src/features/hosts/forms/host-form.tsdashboard/src/service/api/index.ts
🚧 Files skipped from review as they are similar to previous changes (9)
- app/models/subscription.py
- app/core/xray.py
- dashboard/public/statics/locales/ru.json
- dashboard/public/statics/locales/en.json
- dashboard/src/features/hosts/dialogs/host-modal.tsx
- dashboard/src/features/hosts/forms/host-form.ts
- dashboard/public/statics/locales/zh.json
- dashboard/public/statics/locales/fa.json
- dashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsx
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai is that PR ready for merge? Except dependencies, I guess |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== PR state, reviews, and check rollup =='
gh pr view 671 --repo PasarGuard/panel \
--json state,isDraft,mergeable,reviewDecision,statusCheckRollup,reviews,comments \
--jq '{
state, isDraft, mergeable, reviewDecision,
checks: [.statusCheckRollup[]? | {name, status, conclusion, detailsUrl}],
reviews: [.reviews[]? | {author: .author.login, state, submittedAt}],
recentComments: [.comments[-10:][]? | {author: .author.login, body, createdAt}]
}'
echo
echo '== Changed files =='
gh pr view 671 --repo PasarGuard/panel --json files \
--jq '.files[].path'
echo
echo '== Relevant source outlines =='
for f in \
app/core/hosts.py \
app/core/xray.py \
app/models/host.py \
app/models/subscription.py \
app/subscription/links.py \
app/subscription/xray.py \
tests/test_subscription_clash_xhttp.py \
dashboard/src/features/hosts/forms/host-form.ts \
dashboard/src/features/hosts/dialogs/host-modal.tsx \
dashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsx \
dashboard/src/features/hosts/components/finalmask-settings.tsx \
dashboard/src/features/core-editor/components/shared/xray-stream-finalmask-editor.tsx
do
if [ -f "$f" ]; then
echo "-- $f"
ast-grep outline "$f" --items all --view compact 2>/dev/null || true
fi
done
echo
echo '== Focused static consistency searches =='
rg -n -C 2 --glob '*.py' \
'sessionID(Table|Length|Placement|Key)|session_(id_table|id_length|placement|key)|FinalMaskTcpType\.xmc|FinalMaskXmcSettings' \
app tests || true
rg -n -C 2 --glob '*.{ts,tsx,json}' \
'sessionId(Table|Length)|sessionid(table|length|placement|key)|session_id_(table|length)|FinalMaskXmcSettings|["'\'']xmc["'\'']' \
dashboard/src dashboard/public/statics/locales || trueLength of output: 47449 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== Failed Ruff job metadata =='
gh api repos/PasarGuard/panel/actions/jobs/89349573533 \
--jq '{name, status, conclusion, started_at, completed_at, steps: [.steps[] | {name, status, conclusion, number}]}'
echo
echo '== Ruff failure diagnostics =='
gh run view 30049920083 --repo PasarGuard/panel --job 89349573533 --log-failedLength of output: 209659 🏁 Script executed: #!/bin/bash
set -euo pipefail
base_sha=$(gh pr view 671 --repo PasarGuard/panel --json baseRefOid --jq .baseRefOid)
head_sha=$(gh pr view 671 --repo PasarGuard/panel --json headRefOid --jq .headRefOid)
echo "== Changed-line coverage for Ruff diagnostics =="
git diff --unified=0 "$base_sha" "$head_sha" -- \
app/core/hosts.py \
app/core/xray.py \
app/models/host.py \
app/subscription/links.py \
app/subscription/xray.py \
| awk '
/^\+\+\+ / { file=$2; sub(/^b\//, "", file) }
/^@@ / {
if (match($0, /\+[0-9]+(,[0-9]+)?/)) {
range=substr($0, RSTART+1, RLENGTH-1)
split(range, parts, ",")
start=parts[1]
count=(length(parts)>1 ? parts[2] : 1)
if (count == 0) next
end=start+count-1
print file ":" start "-" end
}
}'
echo
echo '== PR changes around potential Ruff diagnostics =='
git diff --unified=4 "$base_sha" "$head_sha" -- \
app/core/hosts.py \
app/core/xray.py \
app/models/host.py \
app/subscription/links.py \
app/subscription/xray.pyLength of output: 10082
What I verified:
The only red check is Ruff. It installs an unpinned latest Ruff ( So the remaining merge prerequisites are:
|
This branch adds Xray 26.6.22+ sessionID compatibility across backend, subscriptions, and the dashboard, and makes the editor/version checks depend on the node's actual Xray version.
xray_version/node_versiondata for nodes, and exposexray_versiononGET /api/core/{id}so the dashboard can make version-aware decisionssessionPlacement/sessionKey->sessionIDPlacement/sessionIDKeyrename across backend config parsing, subscription generation, node upgrade flow, and automatic stored-config migration when a sole node crosses the 26.6.22 thresholdsessionIDTable/sessionIDLengthcontrols to the Hosts UI, including locale stringscoreXrayVersion, includingechForceQuerygating and theallowInsecurehard-error warningsessionIDTable/sessionIDLengthroom-size validation across the Hosts form, inbound dialog, and raw-JSON persist validationDependency Note
dashboard/package.jsoncurrently uses a temporary testing dependency:@pasarguard/core-kitis aliased tonpm:@funlay/core-kit-beta@0.3.0-beta.1, and that build resolves@pasarguard/xray-config-kittonpm:@funlay/xray-config-kit-beta@0.4.0-beta.1indashboard/bun.lock. Before merge, both must be repointed to the official published@pasarguard/*packages, please.Checked
bun run testpasses (19/19), and typecheck is clean for all touched frontend filesuv run pytest tests/api/test_node.py tests/test_subscription_clash_xhttp.py -vis green for the sessionID /xray_versioncoverage in this branchtest_get_nodes_simple_*failures (KeyError: 'access_token') are pre-existing ondev, not introduced herexray_version/node_versioncolumns already exist ondeven/ru/fa/zhare syntactically valid and include the newcoreEditor.inbound.xhttp.*keysechForceQuery/allowInsecuregates on nodes with different Xray versionsSummary by CodeRabbit
New Features
Bug Fixes
sessionID*fields (and prefersessionIDPlacement/sessionIDKey).netselection fallback and tightened session ID validation.Tests
sessionID*keys for XHTTP.