txlyre

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 5038fa1cec i18n: sync 12 locales with en-US — add missing Hosts/subscription keys
  • 709b332d17 feat(hosts): managed Hosts for per-host subscription link overrides (#5409) * test(sub): characterize current link output (externalProxy + single-link baselines) Phase 0 of the Hosts feature. Locks current subscription-link output for the externalProxy paths (vless/vmess/trojan/ss exact, reality/hysteria by Contains) so the upcoming ShareEndpoint refactor can be proven behavior-preserving. These must stay green and unedited through every later phase. * refactor(sub): unify external-proxy link building behind ShareEndpoint (TDD, snapshot-locked) Phase 1 of the Hosts feature. Collapse the duplicated externalProxy link builders (param-form for vless/trojan/ss, object-form for vmess) onto a single ShareEndpoint abstraction so Phase 4 can add Host-driven links with ~zero new branching. Design: an externalProxy-derived endpoint carries the original entry map and applies it through the UNCHANGED applyExternalProxyTLS{Params,Obj} helpers, so output is provably byte-identical. buildExternalProxyURLLinks / buildVmessExternalProxyLinks become thin adapters; the genVless/Trojan/SS/Vmess call sites are untouched. genHysteriaLink is deliberately left on its own path (hex pinSHA256, not pcs). The no-externalProxy default tails are unchanged. TDD: N1-N4 (externalProxyToEndpoint, inboundDefaultEndpoint, buildEndpointLinks, buildEndpointVmessLinks) written failing-first against stubs, then implemented. Mutation sanity (performed + reverted): dropping the ep-carry in externalProxyToEndpoint makes the Phase-0 C1/C2 characterization snapshots go red (TLS overrides vanish), proving the snapshots guard the emitted output. Gate: go test ./internal/sub/... and go test ./... green with ZERO edits to the Phase-0 snapshots; go build ./... green on linux and windows; go vet clean. * feat(model): Host entity + automigrate + openapi codegen (TDD) Phase 2 of the Hosts feature. Adds the Host GORM model: an override endpoint attached to an inbound (address/port + TLS/transport/clash overrides + sub scoping), superseding the legacy externalProxy array functionally while leaving it intact. - model.Host with snake_case column tags, json serializer for slices, text for free-JSON (mux/sockopt/xhttp), validate tags (remark 1-40, port 0-65535, security + mihomoIpVersion enums); TableName "hosts". NodeGuids column is added now but unused (host->node scoping deferred to v2). - Registered in BOTH initModels() (db.go) and migrationModels() (migrate_data.go); the latter is required for cross-DB migration and is easy to miss. PG sequence resync iterates the initModels slice, so it is covered automatically. - pruneOrphanedHosts() deletes hosts whose inbound_id has no inbound, called alongside pruneOrphanedClientInbounds(). - openapigen manifest: Host added to StructAllow with MuxParams/SockoptParams/ XhttpExtraParams -> KindAny; regenerated frontend/src/generated/* + openapi.json. TDD: TestHostTableName, TestHostValidation, TestHostAutoMigrateCreatesColumns (+ _Postgres), TestPruneOrphanedHosts written failing-first against a wrong-name, untagged, unregistered stub, then implemented. Gate: go test ./... green on SQLite AND a real Postgres DSN (local container); go build/vet/gofmt clean; npm run gen succeeds with the new Host type/schema/ example/zod; npm run typecheck + npm run test (542) green. * feat(api): Host CRUD service + controller + routes (TDD) Phase 3 of the Hosts feature. - service/host.go (HostService, empty struct + database.GetDB() like ClientService): GetHosts, GetHostsByInbound, GetHost, AddHost (verifies the inbound exists — no hard FK), UpdateHost (inbound + sort order immutable here), DeleteHost, SetHostEnable, SetHostsEnable, DeleteHosts, ReorderHosts (single driver-safe transaction), GetAllTags. - controller/host.go mirrors NodeController: routes under /panel/api/hosts (list/get/byInbound/tags + add/update/del/setEnable/reorder + bulk/setEnable, bulk/del), binds via middleware.BindAndValidate so the model validate tags are enforced, {success,msg,obj} envelopes. - Wired the hosts group into api.go after nodes (inherits checkAPIAuth + CSRF). - DelInbound now cascades: deleting an inbound deletes its hosts. - Documented all 11 routes in api-docs endpoints.ts (referencing the generated Host schema) and regenerated openapi.json; extended TestAPIRoutesDocumented's controller->basePath switch for host.go. Backend en toast keys added. TDD: service tests (Add/GetByInbound, RejectsUnknownInbound, Reorder, Set/Bulk enable, DeleteHosts, DeleteInboundCascadesHosts, GetAllTags) written failing- first against a nil-returning stub; controller test (AddListGetDelete envelope round-trip + AuthInherited 401) added. Gate: go test ./internal/web/... + go test ./... green; npm run gen + typecheck + lint + test (542) + build green. * feat(sub): render subscription links from hosts; legacy fallback when none (TDD, mutation-checked) Phase 4 of the Hosts feature. Inserts host resolution between inbound and link across all three subscription formats. Mechanism: hostEndpoints(inbound, format) loads the inbound's enabled hosts (filtered by ExcludeFromSubTypes, ordered by sort_order then id) and projects each onto the externalProxy entry shape the raw/json/clash renderers already consume. So a host fans out one link/proxy reusing the exact existing rendering (address/port/security/sni/fp/alpn/pins/ech) with zero new TLS code. Host header and path overrides are applied additively in the raw builders (no-op for legacy externalProxy, which never carries those keys — characterization snapshots stay green). Clash ip-version (MihomoIpVersion) is set last on the proxy. Integration points: - getSubs (raw): per inbound, hostEndpoints AFTER projectThroughFallbackMaster; len>0 -> linkFromHosts (renders only the hosts), else legacy GetLink. - GetJson/GetClash: inject the host endpoints into the inbound's externalProxy before the existing getConfig/getProxies loop. - Precedence: hosts win over any legacy externalProxy (injection replaces it). Backward compat: a zero-host inbound takes the legacy path -> byte-identical output (all Phase-0 characterization snapshots unchanged). TDD: 9 cycles (zero-hosts identical, N-links-ordered with host/path override, disabled skipped, host-vs-externalProxy precedence, no-dedup, sort composes with SubSortIndex, host-over-fallback, resolve-via-client-inbounds, ExcludeFromSubTypes per format) written failing-first against unwired helpers, then wired green. Mutation sanity (performed + reverted, documented here): - zero-hosts fallback: flipping the len(hostEps)>0 guard to >=0 makes TestSub_ZeroHosts_IdenticalOutput go red (host path yields "" for no hosts). - no-dedup: adding a remark-dedup in hostEndpoints makes TestSub_NHosts_NoDedup go red (two distinct hosts collapse to one link). Gate: go test ./internal/sub/... + go test ./... green with ZERO edits to the Phase-0 snapshots; go build green on linux and windows; go vet + gofmt clean. * feat(migration): seed hosts from inbound externalProxy (TDD, idempotent, dual-driver) Phase 5 of the Hosts feature. One-time migration so existing installs surface their legacy externalProxy entries as first-class Host rows. - seedHostsFromExternalProxy() is self-gated on a HistoryOfSeeders "HostsFromExternalProxy" row (run-once) and wired into runSeeders. For each inbound it parses StreamSettings, reads externalProxy[], and creates one Host per entry: forceTls->Security (unknown->same), dest->Address, port->Port, remark->Remark (generated when blank, capped at 40), sni/fingerprint/alpn/ pinnedPeerCertSha256/echConfigList copied; SortOrder=index; InboundId set. - Additive: externalProxy is left intact in StreamSettings (rollback-safe; the sub layer prefers hosts when present, §Phase 4). - Postgres: GORM db.Create advances hosts_id_seq via the sequence, so no extra resync is needed beyond the existing startup resync. TDD: field-mapping, idempotency (second run no-op), no-externalProxy->no-hosts, externalProxy-kept-intact written failing-first against a stub; plus a Postgres counterpart that skips without XUI_DB_DSN. Gate: go test ./internal/web/service/... ./internal/database/... green on SQLite; the *_Postgres tests green against a real Postgres container; go build green on linux and windows; go vet + gofmt clean. (Running the whole database package under XUI_DB_TYPE=postgres is not supported — the SQLite-path tests share the one DSN — so only the t.Skip-gated *_Postgres tests run with the env set.) * feat(ui): Hosts page + schema + query hooks + link preview helper (TDD on schema/helpers) Phase 6 of the Hosts feature — the admin UI. - schemas/api/host.ts: HostFormSchema (validation: remark 1-40, tags ^[A-Z0-9_:]+$ ≤10×≤36, port 0-65535, security/mihomoIpVersion enums, alpn/fingerprint reused from the shared primitives) + a loose HostRecordSchema/HostListSchema for reads. - lib/hosts/host-link.ts: hostToExternalProxyEntry — the frontend mirror of the backend hostToExternalProxyMap (security->forceTls, sni override rules, port inherit), for share-link previews. - api/queries/useHostsQuery.ts + useHostMutations.ts (mirror the node hooks): list/get + add/update/del/setEnable/reorder/bulk; queryKeys.hosts.* added; mutations invalidate keys.hosts.root(). - pages/hosts/{HostsPage,HostList,HostFormModal}.tsx (+CSS) mirroring pages/nodes: list with remark · address:port · inbound · security · tags · enable Switch · per-inbound move up/down (reorder) · bulk enable/disable/delete; form grouped into Basic / Advanced / Clash / Subscription-scope sections. - Route '/hosts' + sidebar item (Global icon); menu.hosts + pages.hosts.* added to the en-US bundle (other locales fall back to English until translated). TDD: HostFormSchema (10 cases) and hostToExternalProxyEntry (6 cases) written failing-first, then implemented. UI verified by lint/typecheck/test/build. Deferred (documented enhancement): the live in-form share-link preview (needs inbound+client context) and a per-host host/path override in JSON/Clash output (raw already overrides; JSON/Clash inherit the inbound's host/path). Gate: cd frontend && npm run lint && npm run typecheck && npm run test (557) && npm run build all green; go build ./... + go test ./... still green. * refactor(ui): remove the External Proxy form from the inbound stream settings Hosts supersede the legacy externalProxy: the subscription renders from hosts (hosts win when both exist) and the migration converts existing externalProxy entries to hosts. externalProxy's only real consumers were the subscription (now covered) and this form's preview — the backend per-client copy-link never used it — so removing the editor has no functional regression. - Drop ExternalProxyForm + toggleExternalProxy from InboundFormModal and delete the orphaned form component + its export; remove its block test + snapshot. - KEEP the externalProxy schema field and backend parsing/link-generation: an existing inbound's externalProxy still round-trips through the form (not silently destroyed on edit) and still renders if a host was removed. Gate: cd frontend && npm run typecheck + lint + test (556) + build green. * fix(ui): use Alert `title` instead of deprecated `message` (antd 6) Ant Design 6 deprecated <Alert message=> in favor of <Alert title=>; the panel was mid-migration (21 Alerts already on title). Renamed the 7 remaining stragglers across 5 files (SubLinksModal, InboundFormModal, sockopt, EmailTab, TelegramTab), silencing the runtime deprecation warning. description= is unchanged. Pre-existing warning, surfaced while testing Hosts — not introduced by it. Gate: npm run typecheck + lint + test (556) + build green. * style(ui): align Hosts page with Clients/Inbounds cards + reorder columns - page-shell.css never listed .hosts-page, so the Hosts page got no content padding / transparent-layout / summary-card spacing. Add a .hosts-page shell block (background, dark/ultra vars, content-area + summary-card padding). This is the actual "card spacing" bug. - HostList: match the Clients/Inbounds list card — hoverable + the toolbar moved into the card title as a .card-toolbar (Add when nothing selected; selected count + bulk enable/disable/delete on selection). Re-declare .card-toolbar in HostList.css since the shared rule lives in a lazily-loaded page stylesheet. - Reorder table columns as requested: Actions, Enable, then Remark, Endpoint, Inbound, Security, Tags. Added scroll x for narrow screens. - HostsPage: add a summary card (Total / Enabled / Disabled) like the other pages. New i18n keys: pages.hosts.selectedCount + pages.hosts.summary.*. Gate: npm run typecheck + lint + test (556) + build green. * style(ui): use Tabs instead of Collapse in the Add/Edit Host form The Basic / Advanced / Clash / Subscription-scope sections are now tabs. Each pane sets forceRender so all fields stay mounted — required because the form uses preserve=false, so an unmounted tab's values would otherwise be dropped on submit (and a required field on a hidden tab still blocks submit). Gate: npm run typecheck + lint + test (556) + build green. * style(ui): split Host form into Security + Advanced tabs; drop unused JSON fields - Remove the Mux/Sockopt/XHTTP raw-JSON fields from the Host form: they were not wired into link generation and the inbound's structured editors are inbound- specific (not reusable). The DB columns + read schema + generated type stay, so they can get proper editors later. (HostFormSchema drops them; HostRecordSchema keeps them.) - Reorganize tabs to Basic / Security / Advanced / Clash / Subscription scope: Security holds the TLS/cert fields (security, sni, sni-overrides, alpn, fingerprint, pins, verify-by-name, ech); Advanced now holds the transport overrides (host header, path). - i18n: add pages.hosts.sections.security; drop the 3 unused field labels. Gate: npm run typecheck + lint + test (556) + build green. * style(ui): restore Mux/Sockopt/XHTTP fields in the Host Advanced tab Put the three free-JSON override fields back, in the Advanced tab next to host header / path (as JSON inputs — the inbound's structured editors aren't reusable here). Re-added to HostFormSchema + defaults + the i18n labels. Gate: npm run typecheck + lint + test (556) + build green. * feat(hosts): add allowInsecure (rendered) + serverDescription/mihomoX25519/vlessRouteId fields Closes most of the Remnawave-host gap analysis. - model.Host: + allowInsecure, serverDescription (≤64), vlessRouteId (0-65535), mihomoX25519. Auto-migrated (SQLite + Postgres verified); openapi regenerated. - allowInsecure is fully RENDERED into subscription output (TDD): - raw link: allowInsecure=1 (TLS/Reality, skipped for none) via the endpoint builder; - JSON/Clash: applyExternalProxyTLSToStream writes tlsSettings.settings. allowInsecure, and clash applySecurity now emits skip-cert-verify for the tls case (it previously only did so for Hysteria — a pre-existing gap, so inbound allowInsecure now renders for vless/trojan/ss clash too). - Frontend: the four fields added to the Host form (allowInsecure → Security, serverDescription → Basic, vlessRouteId → Advanced, mihomoX25519 → Clash); serverDescription shown under the remark in the list. Schema + i18n updated. serverDescription / vlessRouteId / mihomoX25519 are stored + editable; their deeper rendering (and per-host mux/sockopt/xhttp into JSON/Clash, plus a per-host xray JSON template) are tracked as follow-ups. Gate: go test ./... green (SQLite + Postgres for the host schema/migration); go build linux+windows; go vet + gofmt clean; npm run gen + typecheck + lint + test (556) + build green; generated files in sync. * feat(sub): render host sockopt + xhttp-extra params into JSON/Clash output (TDD) A host's sockoptParams and xhttpExtraParams (free-JSON) now take effect: applyHostStreamOverrides injects sockopt into the per-host stream (re-added since the base stream strips it) and merges xhttpExtraParams into xhttpSettings, called in both getConfig (JSON) and getProxies (Clash) right after the per-host TLS apply. No-op for legacy externalProxy entries (keys absent) — characterization snapshots unchanged. mux rendering is outbound-level (overrides outbound.Mux) and needs a genVless/ genVnext/genServer signature change — deferred, along with the per-host xray JSON template. Gate: go test ./internal/sub/... + go test ./... green (snapshots unchanged); go build + vet + gofmt clean. * feat(sub): render host muxParams as a per-host JSON outbound mux override (TDD) genVnext/genVless/genServer take a muxOverride: a host's muxParams (when valid JSON) overrides the global mux on its JSON outbound; empty falls back to the panel mux (behavior unchanged for non-host configs). Completes the host mux/sockopt/xhttp trio. Test call sites updated for the new signature. Gate: go test ./internal/sub/... + go test ./... green (snapshots unchanged); go build + gofmt clean. * style(ui): show Host security fields conditionally per security (like externalProxy) * feat(sub): apply host SNI + fingerprint override for reality (TDD) A reality host now overrides SNI and fingerprint while inheriting publicKey/ shortId from the inbound (reality keys can't be host-supplied). Previously the reality link kept the inbound's serverName because the TLS appliers are gated to security=="tls". - raw: applyEndpointRealityParams sets sni/fp on the params for reality; - JSON/Clash: applyHostStreamOverrides sets realitySettings.serverName + serverNames from the host SNI. Gated to host endpoints via an isHost marker on the synthesized ep, so the legacy externalProxy path stays byte-identical (characterization snapshots unchanged). The marker is internal and never emitted. Gate: go test ./internal/sub/... + go test ./... green; go build + vet + gofmt clean. * fix(ui): start the Host inbound select unselected instead of showing 0 A new host left inboundId defaulting to 0, so the Select rendered "0". inboundId is now optional in the form (undefined until chosen), so it shows its placeholder ("Select an inbound"); the required rule still enforces a choice on save. Port keeps 0 (means "inherit the inbound's port"). Gate: npm run typecheck + lint + build green. * fix(ui): drop redundant :port suffix from the Host inbound select label The inbound tag (e.g. in-59303-tcp) already carries the port, so the appended ":59303" was duplicated. Show just the remark/tag. Gate: npm run typecheck + lint + build green. * style(ui): apply the shared card hover shadows to the Hosts page page-cards.css scoped its card styling + hover shadows to each page class but not .hosts-page, so Hosts fell back to antd's default hoverable (a larger/blurry shadow + pointer cursor). Add a .hosts-page block matching the other pages. Gate: npm run build green. * feat(hosts): move Tags to Basic tab, add Nodes field, accept VLESS route ranges - Move the Tags field into the Host form's Basic tab and add a Nodes multi-select (visual-only assignment, backed by the existing node_guids column) so the Basic tab matches the reference layout. - Replace the single-port vlessRouteId integer with a free-form vlessRoute string that accepts comma-separated ports/ranges (e.g. 53,443,1000-2000); format-validated on the frontend, stored verbatim on the backend. - Regenerated frontend types/openapi from the changed model. * feat(hosts): structured editors for Mux/Sockopt/XHTTP + new Final Mask Replace the raw JSON textareas in the Host form's Advanced tab with the same structured editors used elsewhere, under a nested tabbed layout (General / Mux / Sockopt / XHTTP / Final Mask), mirroring the Sub-JSON settings tab: - Mux: the Sub-JSON mux editor (enable + concurrency/xudpConcurrency/xudp443). - Sockopt + XHTTP: reuse the outbound SockoptForm / XhttpForm, wrapped in an isolated form that serializes the edited subtree back to the host's JSON string (pruned so the override stays sparse). - Final Mask: new host field (model + column + JSON-render wiring that merges the masks into the host's JSON-subscription stream), edited via the shared FinalMaskForm like the Sub-JSON Final Mask editor. Each editor stays a controlled value/onChange component bound to its existing host JSON string field; backend rendering of mux/sockopt/xhttp is unchanged. * feat(hosts): drop XHTTP + Xray-JSON-template overrides; fix mobile form layout Remove the host's XHTTP extra-params and Xray-JSON-template overrides entirely (model fields + columns, JSON-subscription render paths incl. hostTemplateOutbound, schema, form tab/field, i18n, openapi codegen, and their tests) — they did not fit the host model. Mux, Sockopt and Final Mask stay as structured editors. Mobile fixes for the Edit Host modal: - responsive width (95vw on mobile, was a fixed 760px that overflowed the viewport and clipped the tabs/labels) + a scrollable body so the footer stays on screen; - Mux fields use responsive Row/Col (stack on mobile) instead of a fixed-width label grid. * fix(hosts): hide the spurious horizontal scrollbar in the Edit Host modal Setting overflowY:auto on the modal body forced overflow-x to auto too (CSS rule), so antd Row's negative gutter margins triggered a horizontal scrollbar. Pin overflowX:hidden. * feat(hosts): inbound-style responsive field layout + icon empty state - Host form (main form + Mux/Sockopt/Final Mask editors) now use the inbound form's label layout: label beside the input on desktop (labelCol sm span 8 / wrapperCol sm span 14, right-aligned), stacked label-above-input on mobile. Rewrote HostMuxForm onto an internal antd Form so it follows the same layout instead of a manual grid. - Empty hosts table now shows the host icon + the shared 'Nothing here yet' (noData) text, matching Nodes/Inbounds/Clients, replacing the bespoke 'No hosts yet…' string. * fix(hosts): avoid nested <form> in the Edit Host modal The Mux/Sockopt/Final Mask editors each render their own antd Form inside the host's main Form, producing an invalid nested <form> DOM node (hydration warning). Render those inner forms with component={false} so they keep the form instance/context but emit no <form> element. * fix(hosts): make the Mux enable toggle work The Switch's checked state came from Form.useWatch('mux'), but the mux object field had no registered Form.Item while disabled, so setFieldValue never notified the watcher and the toggle stayed off. Bind the Switch to a real name='enabled' field (antd drives its checked state directly) and keep the sub-fields registered via hidden={!enabled}, serialized to the flat mux JSON. * refactor(hosts): reuse the outbound MuxForm instead of a bespoke Mux editor The Mux fields duplicated the outbound MuxForm. Reuse it through the same wrapper as Sockopt: generalize OutboundSubtreeJsonForm with defaultSubtree (pre-fill on enable) and a serialize hook, and have HostMuxForm render MuxForm at the ['mux'] path. The host keeps its inherit-when-off semantics by storing '' unless mux.enabled. Also drops the now-unused enableSwitch path from the wrapper (only the removed XHTTP editor used it). * style(hosts): use default-width Port input like the inbound form The host Port used width:100% (full width); the inbound's numeric inputs use antd's default width. Drop the override so Port matches. The Mux number inputs already use the default width via the reused MuxForm. * refactor(sockopt): readable customSockopt editor as a shared component The customSockopt rows were a single cramped Space.Compact line and duplicated verbatim in the inbound and outbound sockopt forms. Extract a shared CustomSockoptList that renders each entry as a titled group of labeled fields (System / Level / Opt / Type / Value), matching the rest of the form, and use it in both (and thus the host Sockopt editor). * fix(finalmask): drop the empty Custom Tables tag on a new sudoku mask The sudoku TCP-mask default seeded customTables: [''] (one empty string), which rendered as a blank removable tag. Seed [] instead. * fix(sockopt): make the outbound (and host) Sockopt client-only Per the XTLS sockopt docs, tproxy / acceptProxyProtocol / V6Only / trustedXForwardedFor only apply to an inbound (listening socket); they are meaningless on an outbound/dialer. Drop them from the outbound SockoptForm (which the host reuses). The Sockopt default object still seeds those keys, so the host also strips them on serialize, keeping its override honest to the server/client split. The inbound SockoptForm is left unchanged. * fix(sockopt): make the inbound Sockopt server-only Complete the server/client split: drop the outbound/dialer-only fields from the inbound SockoptForm — dialerProxy, domainStrategy, interface, addressPortStrategy, happyEyeballs, tcpMptcp (client-only since Go 1.24 auto-enables MPTCP on listen). mark stays (xray applies SO_MARK on inbound sockets too). Update the form-blocks snapshot to the server-side field set (intentional spec change). * feat(hosts): populate Sockopt dialerProxy with the panel's outbound tags The host Sockopt editor reused the outbound SockoptForm with outboundTags=[], so the dialerProxy dropdown was empty. Feed it the panel's outbound tags via the existing useOutboundTags hook (shares the cached xray-config query; blackhole excluded), so a host can chain through a subscription outbound by tag. * fix(hosts): empty-state styling on direct load + exclude balancers from dialerProxy - .card-empty was only defined in lazily-loaded Clients/Inbounds/Nodes stylesheets, so a direct /hosts refresh rendered the empty table state unstyled (faint + uncentered) until another page was visited. Re-declare it in HostList.css so it's correct on first load. - The Sockopt dialerProxy dropdown listed balancer tags (useOutboundTags merges them in for mtproto egress). dialerProxy chains a single outbound, so balancers aren't valid — switch to useOutboundTagGroups and use only the outbound group. * fix(outbounds): icon + 'Nothing here yet' empty state; stop fading other pages The Outbounds empty state was a faint '—', and OutboundsTab.css set the global .card-empty to opacity:0.4 — which leaked onto whichever page's empty state was shown after the Outbounds CSS had loaded (e.g. Hosts went faint after visiting Outbounds). Render the icon + noData ('Nothing here yet') like the other lists, and align .card-empty to the shared centered/secondary style (no opacity). * fix(outbounds): custom empty state on the desktop table too The desktop Outbounds Table had no locale.emptyText, so it showed antd's default 'No data' box. Add the same ExportOutlined + noData empty state as the card (mobile) view. * style(sidebar): use ExportOutlined for the Outbounds nav item The Outbounds sidebar item used UploadOutlined (an upload tray). Switch to ExportOutlined, matching the outbound icon now used in the routing target and the outbounds empty states. * feat(hosts): icons on the form tabs (icon-only on mobile) Wrap every Host form tab label (Basic/Security/Advanced/Clash/Subscription scope and the nested General/Mux/Sockopt/Final Mask) with catTabLabel, so the tabs show icon + text on desktop and just the icon (with a tooltip) on mobile, matching the Settings/Xray tab bars. * refactor(hosts): fold Exclude-from-formats into Advanced, drop the one-field tab The Subscription scope tab held only excludeFromSubTypes after Tags moved to Basic — a niche per-format scoping knob. Move it into the Advanced > General sub-tab and remove the standalone tab (and its now-unused subScope label/icon). * feat(sub): per-client remark template variables; drop the remark model & Show Usage Info * fix(migration): cap seeded host remark at the model's 256-char limit, not 40
  • Поређење ових 2 комита »

пре 5 часа

txlyre извршује push на master у txlyre/qic

пре 14 часа

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 37c5e0bfd2 feat(node): node hardening — mTLS, hashed+zstd reconcile transport, per-node net metrics (#5382) * fix(api-docs): document clientIpsByGuid route Restores a green `go test ./...` baseline: TestAPIRoutesDocumented flagged POST /panel/api/clients/clientIpsByGuid (added in 9385b6c6) as undocumented in endpoints.ts. * test(node): characterize current node TLS + API auth behavior Phase 0 regression net for the mTLS work. These pass on unchanged production code and lock the pre-mTLS contracts so later phases can be proven additive: - tlsConfigForNode: skip -> InsecureSkipVerify (no VerifyConnection); pin -> VerifyConnection installed. - checkAPIAuth: bearer match -> Next + api_authed; unauthenticated -> 401 (XHR) / 404; valid session -> Next. - panel HTTPS listener with no ClientAuth accepts a client that presents no client certificate (the browsers-keep-working invariant). * feat(crypto): node-auth CA + client-cert minting (TDD) Stdlib-only ECDSA P-256 helpers for the node mTLS work: - GenerateNodeCA: self-signed CA (IsCA, CertSign, path len 0) - IssueClientCert: client-auth leaf (ExtKeyUsageClientAuth) signed by CA - LoadCAFromPEM: parse a CA cert+key for issuing / trust-pool building Tests assert the contract (leaf verifies against the issuing CA with ExtKeyUsageClientAuth), seen failing on the assertion before impl. * feat(node): lazy node mTLS CA + client cert in settings (TDD) SettingService gains opt-in mTLS material, all stored as Setting rows with empty defaults and kept out of entity.AllSetting (so private keys never reach the settings UI/export): - EnsureNodeMtlsCA: mint+persist the node-auth CA once, reuse thereafter - EnsureMasterClientCert: issue the master client cert from the CA, idempotent - NodeMtlsClientCAPool: ClientCAs trust pool for the listener; nil when unconfigured so the no-mTLS path is unchanged Tests assert idempotency and that the client cert verifies against the CA for client auth; seen failing on the assertion before impl. * feat(node): mtls client TLS config + master-cert provider (TDD) tlsConfigForNode gains an 'mtls' branch that presents the master client certificate and verifies the node server against system roots (no InsecureSkipVerify, no custom RootCAs). The cert is supplied via an injected MasterClientCertProvider so runtime need not import service; it fails closed when unconfigured. skip/pin contracts unchanged. * feat(node): allow tokenless mtls nodes in remote do() (TDD) mtls nodes authenticate with a client certificate, so the bearer token becomes optional for them: do() no longer rejects an empty ApiToken when TlsVerifyMode is mtls, and the Authorization header is omitted when no token is set. Every other mode still requires a token (regression kept). * feat(node): authenticate verified client certs in checkAPIAuth (TDD) A completed mTLS handshake (non-empty r.TLS.VerifiedChains) now authenticates an API request, equivalent to a valid bearer token, and sets api_authed so the CSRF middleware lets cert-authed mutations through. Bearer/session/reject paths unchanged. The accept-path assert was mutation-checked (guard flipped -> test red -> reverted). * feat(node): opt-in mTLS on the panel listener (TDD; mutation-checked) web.go now applies VerifyClientCertIfGiven + ClientCAs to the HTTPS listener when a node trust CA is configured, and wires the master client cert provider for outbound mtls calls. With no CA the listener is byte-identical to before (browsers unaffected). applyNodeMtls is covered end-to-end: no-cert client handshakes (browsers keep working), a CA-signed client cert verifies, a foreign-CA cert is rejected at the handshake. Mutation-checked: - RequireAndVerifyClientCert -> no-cert client rejected (red) -> reverted - drop ClientCAs -> master cert no longer trusted (red) -> reverted * feat(node): accept mtls verify-mode + CA reveal endpoint (TDD) - model.Node.TlsVerifyMode validator now accepts 'mtls' - normalize() preserves mtls and requires the node scheme to be https (fail closed), instead of clamping mtls back to verify - NodeService.NodeMtlsCaCert + POST /panel/api/nodes/mtls/ca return this panel's node-auth CA cert (public) to paste into a node, minting the CA + master client cert on first call - endpoints.ts documents the new route (doc-sync test) No model column added (enum is a string), so no migration/codegen. * feat(node): node mTLS UI + trust-CA setter (TDD) Backend: - NodeService.SetNodeMtlsTrustCA + POST /panel/api/nodes/mtls/trustCA store the CA this panel trusts for incoming node-API client certs (validates PEM, empty clears); applied on next restart - endpoints.ts + regenerated openapi.json document both mtls routes Frontend: - node form: 'mtls' TLS-verify option + setup hint (zod enum updated) - Nodes page 'Node mTLS' card: copy this panel's CA, and paste/save the trusted parent CA - en-US i18n keys (other locales fall back to en-US) Gates green: go build (native+windows), vet, go test ./...; frontend typecheck, lint, vitest (541). * style(node): gofmt web_mtls_test doc comment * feat(node): hashed+zstd reconcile transport (TDD, negotiated, mixed-version safe) Adds an integrity + compression envelope to node config pushes: - internal/util/wirecodec: shared zstd codec (bomb-capped decode) + SHA-256 hashing + the header/capability constants - Remote.do(): always attaches X-Config-Sha256 of the uncompressed body; zstd-compresses only when the node advertised support (learned from its X-3x-Node-Caps response header) and the body is >=1KiB - ConfigEnvelopeMiddleware on /panel/api: advertises the cap, decompresses and verifies the hash (handler not invoked on mismatch) before binding Mixed-version safe: old nodes never advertise the cap -> plain bodies; the hash header is verify-if-present so any panel/node mix interoperates (existing reconcile tests stay green). klauspost/compress promoted to a direct dep. Hash-mismatch reject was mutation-checked (compare defeated -> test red -> reverted). * feat(node): per-node network throughput metrics (TDD) The node status response already carries gopsutil netIO.up/down (summed non-virtual interfaces), so no node-side change is needed: - probe() parses netIO.up/down into HeartbeatPatch.NetUp/NetDown - Node gains net_up/net_down columns (AutoMigrate); UpdateHeartbeat persists them and appends netUp/netDown to the per-node metric history - NodeMetricKeys whitelists netUp/netDown so the history endpoint serves them - NodeHistoryPanel renders Net Up/Down sparklines (KB/s, no 0-100 clamp) - regenerated frontend types + openapi.json for the new Node fields * feat(node): move node mTLS controls into a toolbar button + modal The Node mTLS panel was an always-visible card cluttering the nodes page. Replace it with a 'Node mTLS' button beside 'Add node' that opens a modal with the same copy-CA + trusted-parent-CA controls; the modal closes on a successful save. No backend/i18n changes. * i18n(node): translate mTLS + net-metrics keys for all locales Adds the node mTLS strings (tlsMtls, mtlsFormHint, mtls.* dialog + the saveMtls toast) and the netUp/netDown chart labels to all 12 non-English catalogs (ar, es, fa, id, ja, pt, ru, tr, uk, vi, zh-CN, zh-TW), matching each catalog's existing terminology. Technical tokens (mTLS/TLS/CA/API/ KB/s) kept verbatim. * fix(node): address Copilot review on node-hardening PR - setting_mtls: fail closed on a half-present CA/master-cert pair instead of silently regenerating (which would rotate the CA and break fleet trust). - config_envelope: reject non-zstd Content-Encoding on the envelope path rather than hashing/forwarding a still-encoded body to the handler. - node mTLS: support tokenless mTLS end-to-end — apiToken is now required_unless tlsVerifyMode=mtls (model) with matching conditional validation in NodeFormSchema, so the runtime allowance is actually reachable. - NodesPage: add a catch block to onSaveTrustCa so save failures surface.

пре 1 дан

txlyre извршује push на master у txlyre/qic

пре 1 дан

txlyre извршује push на master у txlyre/libqirt

пре 1 дан

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • f3eba04ed8 ci: use .nvmrc for setup-node version in codeql/release workflows
  • 9385b6c609 feat(nodes): per-node client IP attribution for IP-limit Record each panel's own Xray IP observations under its panelGuid and merge each node's guid-keyed report on the master, so the panel can tell which node a client IP is connecting through (the flat inbound_client_ips union is pushed back to every node and cannot attribute). Adds the NodeClientIp model + migration, the clientIpsByGuid endpoint and node-sync merge, node-name labels in the client IP log, and cleanup on node deletion.
  • d882d6aa74 feat(inbounds): add Real client IP presets to capture visitor IP behind CDN/relay Surface the existing sockopt knobs (acceptProxyProtocol, trustedXForwardedFor) as a guided 'Real client IP' preset selector in the inbound form, so the real visitor IP is recovered behind Cloudflare CDN or an L4 tunnel/relay instead of recording the intermediary address. Presets are mutually exclusive, warn on incompatible transports, and add tooltips, docs, and translations for all locales.
  • bbab83db17 refactor(frontend): stack client credential fields and use label hints on inbound form Stack UUID/password/subId/auth/flow/security fields vertically in the client modal instead of two-column rows, and replace the inbound form's 'extra' help lines with hover tooltip hints on field labels.
  • Поређење ових 4 комита »

пре 1 дан

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • dc781b28c4 chore(deps): bump telego to v1.10.0
  • 5b8504c756 chore(deps): bump frontend deps and override js-yaml to patch DoS advisory Force swagger-ui-react's bundled js-yaml to ^4.2.0 (GHSA-h67p-54hq-rp68) without downgrading swagger-ui-react. Also picks up minor bumps to antd, axios, react-router-dom and dev deps.
  • c1fdcd98d2 fix(nodes): route 'load inbounds' through the connection outbound Loading a node's inbound list bypassed the configured connection outbound and dialed the remote panel directly, so a node only reachable through that outbound timed out with 'context deadline exceeded' even though Test Connection succeeded. Extract the temporary loopback SOCKS5 bridge setup from ProbeWithOutbound into a shared withOutboundBridge helper and route GetRemoteInboundOptions through it when an outbound tag is set.
  • eec030f86f feat(notifications): event bus architecture with Telegram and SMTP subscribers (#5326) * feat(notifications): event bus architecture with Telegram and SMTP subscribers - Event bus core with buffered channel, fan-out, panic recovery - Telegram subscriber with HTML formatting and rate limiting - Email subscriber with SMTP/TLS/STARTTLS support and stage diagnostics - 5 event types: outbound.down/up, xray.crash, cpu.high, login.attempt - CPU threshold checks per subscriber (tgCpu for TG, smtpCpu for Email) - SystemMetricData struct for raw metric values in events - i18n keys for en-US, ru-RU, and English defaults for other locales * fix * fix(notifications): repair crash/CPU alerts, harden secrets, add node alerts Bug fixes: - Xray crash notifications were permanently suppressed after the first crash: XrayStateTracker latched state="down" with no reset and no recovery event, so only the first crash per process lifetime ever notified. Removed the tracker; the existing 1/min rate limiter already dedupes crash-loop spam. - Email CPU alerts could never fire unless Telegram was also enabled, because the CPU job was registered only inside the tgbot block. Register it whenever either Telegram or SMTP wants cpu.high (new cpuAlarmWanted gate) and relax the cadence to @every 1m (cpu.Percent already samples over a full minute). - SMTP password (and, pre-existing, all other secrets) were shipped to the browser in plaintext: GetAllSettingView was dead code and /setting/all returned the raw model. Wire getAllSetting -> GetAllSettingView, redact smtpPassword with a hasSmtpPassword presence flag, and preserve it on blank save. Closes the leak for tgBotToken/ldapPassword/2FA token too. Polish: - email Send: use nil SMTP auth when no credentials (Go refuses PlainAuth over the unencrypted "none" transport). - Remove unused EventClientDepleted; fix inaccurate bus.go doc comments; drop stale tgBotLoginNotify from the frontend schema; gofmt alignment. Feature - node online/offline alerts: - Emit node.down/node.up from the heartbeat job on a real status transition (with a startup-spam guard), reusing NodeHealthData. Formatted by both the Telegram and email subscribers and selectable in the settings UI. Regenerated frontend types (hasSmtpPassword). New i18n keys added to en-US; other locales fall back to English (bundle default) until translated. * fix(settings): use antd Space orientation instead of deprecated direction Ant Design 6 deprecated Space's `direction` prop in favor of `orientation`, which logged a console warning from the Telegram/Email notification tabs. Brings these two tabs in line with the rest of the codebase, which already uses `orientation`. * i18n(notifications): translate the notification feature into all locales The notifications PR shipped ~99 new strings (SMTP settings, event labels, Telegram/email message templates) as English placeholders in every non-English locale. Translate them — plus the node-alert keys added during this review — into all 12 locales: Arabic, Spanish, Persian, Indonesian, Japanese, Portuguese-BR, Russian, Turkish, Ukrainian, Vietnamese, and Simplified/ Traditional Chinese. Go-template placeholders ({{ .Tag }}, {{ .Name }}, etc.) are preserved exactly; tgbot message values carry no leading status emoji (the bot/email code adds those, so an emoji in the value would duplicate it); product/protocol names (SMTP, STARTTLS, TLS, CPU, Xray, Telegram) are kept as-is. --------- Co-authored-by: Sanaei <[email protected]>
  • 7fe082a7f1 fix(nodes): stop multi-attached client traffic inflating across node inbounds Xray counts client traffic globally per email, so a client attached to several of a node's inbounds has its single shared counter copied onto every inbound by the node's enriched inbound list. When those copies diverge (legacy per-inbound rows surviving a v3.2.x->v3.3.x upgrade, or any drift) the per-inbound delta loop read the lower sibling as a node-counter reset and re-added its full value, inflating the client far past real usage (#5274). Fold each email to its per-field node-wide max before the delta loop so every occurrence is equal: the per-email baseline dedup then holds and the reset clamp never misfires.
  • Поређење ових 17 комита »

пре 1 дан

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 53f6ed394f Add Enable/Disable Toggle for Xray Routing Rules (#5296) * feat: add enable/disable toggle for xray routing rules * fix(routing): never let the internal api rule be disabled The Enable/Disable toggle could strip the stats api rule: its table switch was locked, but the rule-form modal's Enable dropdown was not, and stripDisabledRules had no api-rule guard (EnsureStatsRouting's delete only runs when the api rule isn't already first). A disabled api rule then dropped out of the generated config and broke traffic accounting. - stripDisabledRules now always keeps the api rule, even if marked disabled, and strips the panel-only enabled key from every rule - extract isApiRule helper (backend + frontend) and reuse it across the table switch, card switch, and form modal - disable the form-modal Enable dropdown for the api rule - add stripDisabledRules tests covering the api-rule survival path --------- Co-authored-by: Sanaei <[email protected]>
  • 66a9a788fc fix(reality): load `dest` as `target` alias so existing inbounds aren't wiped (#5295) xray-core accepts both `target` and `dest` for the REALITY destination (infra/conf/transport_internet.go: REALITYConfig has json:"target" and json:"dest"). The frontend schema only knows `target`, so an inbound whose realitySettings use `dest` — older panel builds, external tools, or the panel's own /panel/api/inbounds API — loads with an empty (required) Target field even though xray is running fine. Re-saving then serializes the blank `target` and drops the working `dest`, breaking REALITY on the next restart. Normalize `dest` -> `target` on parse (z.preprocess) when `target` is absent/empty, matching xray-core's alias behavior. Add unit tests covering the schema directly and through the security discriminated union. Co-authored-by: Volov <[email protected]>
  • dab0add191 feat(finalmask): support Salamander packetSize (Gecko) and Realm tlsConfig for Hysteria2 (#5278) * feat(finalmask): support salamander packetSize (Gecko) and realm tlsConfig Hysteria v2.9.1/v2.9.2 added two finalmask features that the pinned Xray-core (26.6.1, 94ffd50) already supports but the panel UI did not expose: Salamander's packetSize range (Gecko, XTLS/Xray-core#6198) and the Realm UDP hole-punching mask's optional tlsConfig (XTLS/Xray-core#6137). Add typed schemas and form fields for both, keeping UdpMaskSchema.settings permissive per the existing finalmask design note. packetSize reuses the existing dash-range preprocess (like udpHop.ports) so it round-trips under the fm= share-link param with no new URI key; realm tlsConfig emits xray's flat TLSConfig shape (serverName/alpn/fingerprint/allowInsecure). Verified against the bundled Xray 26.6.1: configs with packetSize and realm tlsConfig validate (Configuration OK.), plain salamander stays backward-compatible, and a malformed packetSize is correctly rejected by the salamander mask builder. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * test(finalmask): add snapshots for salamander-gecko and realm-tls fixtures vitest run does not auto-create missing snapshots in CI mode, so the two new fixtures need committed snapshot entries. Verified under node:22 that finalmask.test.ts passes (6/6) with these snapshots. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * feat(finalmask): polished Gecko UX with core-grounded validation Fold PR #5281's Gecko work into the Realm tlsConfig base: - Replace the plain packetSize input with a Salamander/Gecko mode selector and validated Min/Max number inputs. - parseGeckoPacketSize enforces xray-core's real bound (1 <= min <= max <= 2048, the gecko buffer size) so the panel rejects configs core would reject at runtime. - Accurate Gecko description; add parser unit tests. - Drop the unused Salamander/Realm settings schemas; settings stay permissive and are validated at the form level. --------- Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]> Co-authored-by: Sanaei <[email protected]>
  • 7c737820d1 fix(links): bracket ipv6 hosts in share links and qr codes (#5310) * fix(sub): bracket ipv6 hosts in share links * fix(frontend): bracket ipv6 hosts in share links
  • 335470607f fix(ui): match node connection-outbound picker to panel-outbound selector Group the tags into Outbounds/Balancers, hide blackhole outbounds, and show the 'Direct connection' placeholder on empty via getValueProps so the field never looks unset and an empty default can't read as a second 'direct'.
  • Поређење ових 13 комита »

пре 2 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 7c2598fae9 feat: release-driven golden-image & unattended-install deployment pipeline (#5323) * feat(install): add non-interactive install path for cloud/golden-image use Trigger non-interactive mode when XUI_NONINTERACTIVE=1 or stdin is not a TTY (curl | bash, cloud-init). Every prompt is then replaced by an env var or a sane default; interactive prompts stay byte-for-byte identical. Honored env vars: XUI_USERNAME, XUI_PASSWORD, XUI_PANEL_PORT, XUI_WEB_BASE_PATH (unset => random, as before), XUI_SSL_MODE=none|ip|domain (default none), XUI_DOMAIN, XUI_ACME_EMAIL, XUI_DB_TYPE/XUI_DB_DSN, plus additive XUI_ACME_HTTP_PORT, XUI_SSL_IPV6, XUI_SERVER_IP. On success, write /etc/x-ui/install-result.env (mode 600) with the panel creds + access URL + api token, in both interactive and non-interactive modes, so cloud-init/MOTD can surface them. Postgres in non-interactive mode requires XUI_DB_DSN or installs locally; never silently downgrades. * feat(deploy): add first-boot per-instance credential generation Golden images ship with no x-ui.db. x-ui-firstboot.sh runs once (guarded by /etc/x-ui/.firstboot-done), before x-ui.service, and replaces the seeded admin/admin with fresh random username/password on a random high port, regenerates the session secret/panel GUID via 'x-ui setting -reset', mints an API token, and writes the creds to /etc/x-ui/credentials.txt (600) + /etc/motd. Idempotent: skips regeneration if a non-default admin already exists. The oneshot unit is ordered After=network-online/cloud-init and Before=x-ui.service so the panel never serves default credentials. * chore(deploy): force LF for cloud-image deploy assets (.service/.hcl/.yaml) * feat(deploy): add Packer config + provisioning scripts for golden image One build, two sources: amazon-ebs (AWS AMI, Canonical Ubuntu 24.04 base via source_ami_filter) and qemu (qcow2 + raw, NoCloud-seeded for build-time SSH). Provisioner order is fixed: provision.sh -> harden.sh -> cleanup.sh. - provision.sh: downloads the released x-ui tarball (no Go build), installs the panel + firstboot unit, enables but does NOT start services, creates NO DB. - harden.sh: key-only SSH, no root password login, locks default account passwords, enables unattended-upgrades (scanner-compliant). - cleanup.sh: wipes any DB/creds, SSH host keys, authorized_keys, machine-id, cloud-init state, logs and history; fails the build if any secret survives. packer fmt -check clean; packer validate passes for both sources. * feat(deploy): add generic cloud-init user-data for unattended install cloud-init.yaml installs the latest 3x-ui non-interactively (XUI_NONINTERACTIVE=1) on any cloud-init platform, generating unique per-instance credentials and surfacing them via /etc/x-ui/install-result.env, serial console and MOTD. README documents per-provider usage (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle) and all XUI_* knobs. * ci: add image.yml to build cloud images on release On release: published (or workflow_dispatch with a tag), waits for the x-ui-linux-amd64.tar.gz asset (handles the release-matrix upload race), then: - qemu-image (always): builds the qcow2 with Packer and attaches a compressed .qcow2.xz + sha256 to the GitHub release. Uses KVM when /dev/kvm exists, else TCG. - ami-image (gated): builds the AWS AMI only when AWS creds exist (OIDC role preferred, else access keys), so forks skip cleanly. Prints the AMI ID to the job summary. No secrets or AMI IDs are committed. * test(deploy): add container smoke tests for install + firstboot smoke-noninteractive.sh: runs install.sh piped (no TTY) with XUI_NONINTERACTIVE=1 in an Ubuntu container; asserts install-result.env (600) holds random non-default creds, hasDefaultCredential is false, and the panel serves HTTP. smoke-firstboot.sh: installs the released binary with no DB, runs x-ui-firstboot.sh; asserts per-instance creds + credentials.txt (600) + MOTD, no admin/admin, and that a second run is a no-op (sentinel honored). smoke.yml runs both as gated jobs on PRs/pushes touching install.sh or deploy/**. Both pass locally against the v3.3.1 release binary. * docs(deploy): add Packer/marketplace docs and link from README - deploy/README.md: index of the cloud-deploy tooling and the two models - deploy/packer/README.md: how to build locally, variables, first-boot behavior - deploy/marketplace/aws/README.md: seller registration -> AMI scan -> limited-visibility preview -> go-public checklist - deploy/marketplace/hetzner/README.md: cloud-init-first guidance + snapshot caveat (delete x-ui.db first) + hetznercloud/apps reference - README.md: link the unattended-install / cloud-image docs from Quick Start * feat(deploy): build golden images for arm64 as well as amd64 The install path was already multi-arch (install.sh auto-detects arch); this extends the golden image + CI to arm64: - packer: xui_arch (amd64|arm64, validated) now derives the base AMI filter and the Ubuntu cloud image; the qemu source switches to qemu-system-aarch64 + virt machine + AAVMF UEFI firmware for arm64. amd64 path unchanged. - image.yml: arch matrix. AMIs for amd64 (t3.small) + arm64 (t4g.small/Graviton) from one runner; qcow2 for amd64 on a standard runner and arm64 on a native ubuntu-24.04-arm runner. Waits for both release tarballs. - smoke.yml: run install + firstboot smoke tests on amd64 and arm64 runners; smoke-firstboot.sh now resolves the arch tarball via dpkg. - docs updated for both arches. packer fmt/validate pass for amd64 and arm64; actionlint + shellcheck clean. Verified locally: non-interactive install AND firstboot run on the real arm64 release binary under emulation (ELF aarch64, no admin/admin). * chore(deploy): default AWS region to eu-central-1 (Frankfurt) Replace the us-east-1 fallback in image.yml (4 sites) and the Packer 'region' default + doc examples. Still overridable via the AWS_REGION repo variable / the -var 'region=...' flag. * feat(deploy): add Amazon Lightsail support (launch script + snapshot builder) Lightsail can't launch from an EC2 AMI and its blueprint list isn't self-publishable, so add the two self-service paths instead: - launch-script.sh: paste into Lightsail 'Add launch script' (or --user-data) to install 3x-ui non-interactively with unique per-instance credentials. - snapshot-userdata.sh + build-snapshot.sh: AWS CLI pipeline that provisions a build instance (panel installed, NO DB, firstboot enabled), runs the shared cleanup.sh, then snapshots it. Instances launched from the snapshot mint their own credentials on first boot. Optional --panel-port pins a known port for the Lightsail firewall. - README documents both paths, the firewall caveat, and the blueprint reality. EC2 AMI / Marketplace path kept untouched alongside. All scripts shellcheck-clean. * fix(deploy): address Copilot PR review findings - install.sh + firstboot: write install-result.env / credentials.txt values with printf %q so the files stay safe to source even if creds are pinned with shell metacharacters (no-op for the alphanumeric random defaults). - firstboot: fail closed if 'x-ui setting -show' can't be parsed to true/false — exit without writing the sentinel so the next boot retries, instead of silently skipping regeneration and risking admin/admin. - firstboot + cloud-init + lightsail launch-script: keep secrets out of the world-readable /etc/motd (show URL + username only; full creds via the mode-600 file / serial console). - lightsail build-snapshot: handle download-default-key-pair returning either a PEM or base64, and assert a valid PEM before using it for SSH. - image.yml: pin hashicorp/setup-packer@v3 (was @main). - deploy/README: document XUI_ACME_HTTP_PORT / XUI_SSL_IPV6 / XUI_SERVER_IP. Both container smoke tests still pass; shellcheck + actionlint clean.

пре 2 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 1c0fdb4527 fix(outbounds): test subscriptions in Test All, skip direct/dns Test All only iterated the editable template outbounds, so subscription outbounds (the read-only "from subscriptions" table) were never probed in bulk. They are now queued too, keyed by tag in subscriptionTestStates so their rows light up live; the template and subscription HTTP lanes run serially to respect the backend's single-batch lock (TCP runs alongside). Also stop testing freedom ("direct") and dns outbounds: they aren't proxies, so an HTTP probe through them only measures the host's own reachability, not a tunnel. They are now untestable in every mode -- the per-row button is disabled and Test All skips them -- with a matching backend guard so a direct API caller can't HTTP-test them either.
  • 2d6dea4bf6 fix(settings): rename remark model 'Other' to 'External Proxy' (#5265) The 'o' remark block is sourced from an external proxy's remark, but the label 'Other' gave no hint where to set it. Rename the display label to 'External Proxy' to match the inbound form section; the stored 'o' key is unchanged so existing remarkModel values stay compatible.
  • 4c8d3cb625 fix(nodes): honor TLS verify mode skip/pin for remote node operations (#5264) The node probe honored the per-node TlsVerifyMode (skip/pin) but runtime.Remote used a shared client with no TLSClientConfig, so traffic sync and every other remote op fell back to system-CA verification and failed against self-signed nodes even after the operator set skip/pin. Move the TLS client builder into the runtime layer (HTTPClientForNode / DecodeCertPin) as the single source of truth, have Remote build and cache its per-node client through it, and delegate the service probe to the same builder so the two paths can no longer diverge.
  • 9a8247fa78 fix(tgbot): clear legacy panelProxy/tgBotProxy settings on upgrade v3.3.1 removed the Panel Proxy URL field from the UI but left the stored panelProxy/tgBotProxy values in the DB. The Telegram bot still reads tgBotProxy directly, so a stale value masked the panelOutbound egress fallback. Add a one-off seeder to drop both rows. Closes #5266
  • 355262e632 fix(clients): keep the client list live with a background poll (#5262) The paged client list is sorted/paginated server-side but fetched with staleTime: Infinity, so the WS client_stats patch only refreshed traffic on already-visible rows — newly connected clients never appeared and the sort order went stale until a manual refresh. Add a 5s refetchInterval so the current page tracks reality, and drive the table overlay off isPlaceholderData so the background poll does not flash it.
  • Поређење ових 6 комита »

пре 4 дана

txlyre синхронизује се v3.3.1 у txlyre/3x-ui из огледала

пре 4 дана

txlyre синхронизована нова референца v3.3.1 y txlyre/3x-ui из огледала

пре 4 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 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.
  • 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.
  • 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.
  • b5ef412b8d v3.3.1
  • 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.
  • Поређење ових 7 комита »

пре 4 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 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.
  • 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.
  • 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.
  • 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.
  • 90e6217749 fix(inbound): preserve custom share strategy on edit (#5225)
  • Поређење ових 18 комита »

пре 5 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 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
  • 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.
  • 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.
  • 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".
  • 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.
  • Поређење ових 5 комита »

пре 5 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • Поређење ових 24 комита »

пре 5 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 58905d81a4 feat(node-sync): push global client usage to nodes for display and local enforcement A client attached to several panels has one aggregated row on each master, but a node only ever saw its local share: the node UI under-reported usage, and the node kept serving a client whose cross-panel total had already exceeded its quota — the master's disable push doesn't kill established connections unless the node restarts xray itself. Masters now push their aggregated per-client counters to each node from NodeTrafficSyncJob (throttled, scoped to the clients that node hosts). The node stores them in the new client_global_traffics side table keyed by (masterGuid, email), overwritten on every push so a master-side reset propagates, and: - overlays max(local, pushed) onto UI read paths (slim inbound list, inbound detail, clients list, WS stats, per-email lookups). The full /panel/api/inbounds/list stays un-overlaid on purpose: it doubles as the traffic snapshot masters poll, and overlaying it would corrupt every master's delta accounting; - trips disableInvalidClients when any master's pushed total exceeds the client's quota, so the existing RestartXrayOnClientDisable flow disconnects the client locally; - clears the side rows on traffic reset, auto-renew, and client delete, keeping a renewed quota window clean. Supersedes #5204, which folded pushed globals into client_traffics and compensated with read-back baselines — that double-counted first-sight emails and could not work with several masters sharing one node.
  • 8258a26fbf fix(node-sync): keep shared client traffic row when email still lives on other inbounds client_traffics is the per-email accumulator shared across every inbound and node the client is attached to. setRemoteTrafficLocked deleted it unguarded in two sweeps — when a node inbound vanished from the snapshot (node reinstall, tag change, another master's reconcile on a shared node) and when an email left one inbound's stats — even though the email was still attached elsewhere. The next sync then re-seeded the row with that node's counter alone, so the panel showed the last changed panel's number instead of the summed total. Guard both sweeps with emailUsedByOtherInbounds, matching what the manual-edit path (updateClientTraffics) already does. Truly removed clients are still cleaned up by the zero-attachment sweep.
  • dc52e725b6 fix(ui): blink the online dot in mobile client cards like desktop The mobile card rendered a static antd Badge for every bucket. When the client is enabled, online, and not depleted, render the same animated online-dot span the desktop Online column and the nodes list use.
  • aeb2217ae5 fix(ui): classify ended clients as depleted, not disabled, on inbounds page The auto-disable job flips client.enable off in the settings JSON when a client expires or exhausts its traffic, so the inbounds-page rollup filed every ended client under the gray Disabled badge (and double-counted it in Depleted when stats were present). Classify with depleted-first priority, matching computeClientsSummary and the client info modal. Also backfill cross-inbound client_traffics rows in GetInboundsSlim: the row is keyed on email and only preloads on the inbound the client was created on, so on every other attached inbound the depleted/expiring checks could never fire.
  • 9730561f20 ci(bot): update issue-bot repo map and tighten reply style - Refresh repository map: add internal/mtproto, web/entity, web/global, web/session, web/locale, frontend/, tools/openapigen, docs/, windows_files - Correct stack facts: Xray-core runs as a managed child process; full env var list incl. XUI_INIT_WEB_BASE_PATH, XUI_LOG_FOLDER, XUI_BIN_FOLDER, XUI_SKIP_HSTS; protocol list matches the model.go enum incl. MTProto - Add COMMENT STYLE section for professional, precise, answer-first replies - Raise --max-turns for both jobs
  • Поређење ових 11 комита »

пре 6 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • eee652c4a5 chore(deps): bump golang.org/x/net from 0.55.0 to 0.56.0 (#5199) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.55.0 to 0.56.0. - [Commits](https://github.com/golang/net/compare/v0.55.0...v0.56.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.56.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • 1ad483ede6 fix: expose streamSettings for Tunnel inbounds to support TProxy (#5171) * fix: expose streamSettings for Tunnel inbounds to support TProxy * fix(ui): hide security tab for tunnel inbounds when stream is enabled tunnel (dokodemo-door) does not support TLS or Reality, so showing the security tab only results in a fully-disabled radio group. Exclude tunnel alongside wireguard from the security tab. * fix(tunnel): restrict stream tab to sockopt-only and fix transportless schema Tunnel (dokodemo-door) only needs sockopt.tproxy for TProxy mode — no user-selectable transport. Add hasSelectableTransport flag to hide the network picker, per-network sub-forms, ExternalProxy, and FinalMask for both tunnel and wireguard, matching the pattern already used for Hysteria. Fix a pre-existing Zod schema bug where NetworkSettingsSchema was a bare discriminatedUnion requiring `network` to be present. Wireguard and tunnel submit streamSettings without a `network` key, causing "Invalid discriminator value. Expected 'tcp' | ..." on every save. Fix by adding a transportless union branch (z.never().optional()) alongside the transport DU; also add ?? 'tcp' fallback in inbound-link.ts where stream.network is now string | undefined. Three regression tests added. --------- Co-authored-by: rqzbeh <[email protected]> Co-authored-by: MHSanaei <[email protected]>
  • Поређење ових 2 комита »

пре 6 дана

txlyre синхронизује се main у txlyre/3x-ui из огледала

  • 57e9661758 fix: properly configure fail2ban backend and dependencies on Ubuntu 22.04+ (#5159) (#5184) Co-authored-by: rqzbeh <[email protected]>
  • 65fa40b819 fix: accurately retrieve and generate API tokens via CLI with hashed storage (#5145) (#5183) Co-authored-by: rqzbeh <[email protected]>
  • f88f53cd7b fix(update): restart panel after regenerating webBasePath to fix login desync When update.sh regenerates a short webBasePath, it writes the new path to the database after the panel is already running with the old path loaded in memory. Without a restart the server keeps serving the old path while the UI shows the new one, making the new path unreachable.
  • ca4f32e3da feat: replace panel proxy URL with outbound-based egress bridge Instead of requiring a manual SOCKS5/HTTP URL, the panel now lets the admin pick an Xray outbound from a dropdown (same UX as Geodata Auto-Update). At runtime, injectPanelEgress appends a loopback SOCKS inbound (tag: panel-egress) and prepends a routing rule so the panel's own HTTP traffic — version checks, Telegram, normal geo-file updates — is routed through the chosen outbound. Xray-native Geodata Auto-Update is unaffected (it uses its own geodata.outbound inside Xray). Blackhole outbounds are excluded from both picker dropdowns since routing any download through one just drops it. Translations updated for all 13 locales.
  • 6b16d8c37a feat: apply inbound/outbound/routing changes live via Xray gRPC API Add a hot-apply layer that computes a diff between the old and new generated config and applies only the changed parts through the Xray gRPC HandlerService and RoutingService, avoiding a full process restart whenever possible. A restart is still performed when sections that have no reload API (log, dns, policy, observatory, ...) actually change. Key additions: - internal/xray/hot_diff.go: ComputeHotDiff with canonical-JSON comparison (sorted keys, null=absent, full number precision) so UI reformatting never triggers a spurious restart - internal/xray/api.go: AddOutbound/DelOutbound, ApplyRoutingConfig, GetBalancerInfo, SetBalancerTarget, TestRoute gRPC wrappers - internal/web/service/xray.go: tryHotApply, ensureAPIServices, GetBalancersStatus, OverrideBalancer, TestRoute service methods - internal/web/controller/xray_setting.go: balancerStatus, balancerOverride, routeTest API endpoints - frontend: BalancersTab live-status/override columns, RouteTester component, Restart button removed (Save now hot-applies) - balancer-helpers.ts: syncObservatories never creates observatory sections for random/roundRobin balancers (no reload API → restart) - i18n: balancerLive/Override/routeTester keys added to all 13 locales
  • Поређење ових 5 комита »

пре 6 дана

txlyre синхронизоване и избрисане референце copilot/fix-github-actions-build-windows y txlyre/3x-ui из огледала

пре 6 дана