txlyre

txlyre synced commits to main at txlyre/3x-ui from mirror

  • 12d51d7195 perf(tests): copy a migrated template DB instead of migrating per test Most tests opened a throwaway panel DB with database.InitDB, which runs the full AutoMigrate + seed on an empty file every time: ~230ms, and ~850ms under -race because GORM's reflection-heavy migration is what the detector slows most. internal/web/service does this in ~550 of its 830 tests, so the CI race job spent ~10 of its ~14.6 minutes re-migrating empty databases. internal/database/dbtest.InitDB migrates once per test process, then hands each test its own copy of that file (~130ms under -race) and registers the CloseDB cleanup. The copy then goes through InitDB like a panel restart, so every test still starts from the state a fresh install has. Tests that reopen an existing file, migrate a hand-built legacy DB or target Postgres keep calling database.InitDB. Locally under -race: internal/web/service 626s (last CI run) -> 114s, internal/sub 246s -> 35s.
  • 33a469315a feat(clients): preserve traffic counters in portable export/import (#6469) * feat(clients): preserve traffic counters in portable export/import ExportAll now attaches client_traffics up/down (plus resetCount and last-seen fields) on each portable payload, and ImportClients restores them only for newly created emails so skipped/existing clients keep their live counters. Fixes #5858. * fix(clients): restore imported traffic only onto rows the import created Review of the portable-traffic export/import (#5858) found four defects: - An orphan's restored row was hand-built, dropping reset_weekday and forcing enable=true; a row kept by a keepTraffic delete kept the old client's limits. depletedClientsClause then matched a weekly-renewing over-quota orphan and DelDepleted deleted it. Orphan rows now go through AddClientStat, whose upsert refreshes config and keeps counters, so the unused traffic.total field is dropped from the export. - Created clients were inferred from Skipped emails, so a duplicate email in the file left the created copy with zero counters. bulkCreate now reports which payloads inserted a record, and only those are restored. - Each client took its own serialized-writer commit: 2000 clients spent 3.66s instead of 0.52s. Counters now apply in batched transactions (0.51s). - importClients discarded needRestart when the late restore step failed after clients were committed; it now flags and notifies first, as create already does. The /clients/export and /clients/import API docs now describe traffic. * fix(groups): keep imported traffic out of group totals Group totals keep a deleted client's usage (#5675), and the portable import restores that same usage onto the re-created client. Export, delete, re-import therefore counted it twice in ListGroups, and a fresh panel showed the migrated usage as consumption of its groups. Restored counters are usage from before the import, so the import now shifts each group's baseline up by what it restored, in the same transaction. A group total no longer moves at import time; only traffic consumed afterwards counts. The baseline shift reuses the #5675 helper, now signed. --------- Co-authored-by: Sanaei <[email protected]>
  • ac43b19cfa chore(ci): stop release and CodeQL runs on PRs, drop deploy smoke tests The release matrix (7 Linux cross-builds + a CGO Windows build) ran on every PR and on every branch push, so a PR from a repo branch built everything twice. Release binaries now build only on main (dev channel) and version tags; any other branch can still be built via workflow_dispatch. CodeQL keeps its push-to-main and weekly scans but no longer runs per PR. The deploy smoke workflow fired on every Release completion only to skip its jobs; deploy/test/smoke-noninteractive.sh stays for manual runs.
  • 0ef94b686e feat(tgbot): add /broadcast to relay an admin message to all clients (#6510) * feat(tgbot): add /broadcast to relay an admin message to all clients Admins had no way to reach every client at once: notifications only cover exhausted quotas, so an operator had to copy a message to each client chat by hand. Add an admin-only /broadcast flow to the bot: - /broadcast asks for a message; any message the admin sends — text, rich text, photo, video, file, sticker or a whole album — becomes the broadcast by reference (admin chat + message ids), and a preview self-copy shows the admin exactly what recipients will get while rejecting content Telegram cannot copy before the run starts. - The draft references the original instead of parsing its content, so copyMessage/copyMessages deliver everything 1:1 on behalf of the bot with no forward header (the admin's identity stays private), no caption length pitfalls, and future Telegram message types work without new parsing. - A media group arrives as separate updates; its ids are buffered with a short debounce, sorted, and delivered as one copyMessages call so recipients see the original album. - Delivery runs in a background goroutine (common.GoRecover): sequential sends with a small pause, 429 retry_after honored per recipient, failures counted without stopping the run, progress edited into one card at most every 25 sends or 3 seconds, a cancel button checked between sends, and a final delivered/failed/skipped summary. The summary is edited into the card (only sent separately if the card is gone), so it is never duplicated. - Recipients repeat the notifyExhausted walk: clients with a linked tg_id, deduplicated, admins excluded — they already receive the reports. The message content is never logged. New i18n keys are added to all 13 locales. * fix(tgbot): harden broadcast composition per review - Key the composition per admin chat instead of one process-wide draft: two admins can now compose at once without dropping each other's drafts, and one admin's /broadcast no longer wipes another chat's half-collected album. - Bind each preview card to its own draft via a random token carried in the confirm callback, so a stale Send tap is answered with an error instead of delivering a newer, unapproved draft. - Ignore non-admin senders while a chat composes: the awaiting state is keyed by chat id, and in a group that chat is shared. - Check the cancel flag inside the flood-control retry loop, so a 429 with a long retry_after no longer holds the single broadcast slot after the admin cancelled. - Scale the per-recipient pause by the copied batch size, so an album keeps the same per-second ceiling as a single message. - Trim the comment blocks that exceeded the two-line cap. * fix(tgbot): reset broadcast state on stop and classify 403 as skipped - Clear compositions and cancel the active run from StopBot, next to the per-chat draft resets: an album debounce timer, a confirmable token or a held runner slot must not outlive the receiver that created them. - Sleep flood-control waits in 5 s slices and re-check cancel and bot state between them, so a minutes-long retry_after no longer parks the single-runner slot after the admin cancelled or the bot stopped. - Count Telegram 403 (the chat never started the bot, or blocked it) as skipped instead of failed, log it at debug rather than one warning per recipient, and append one line to the summary naming the reason. - Trim the remaining comment blocks over the two-line cap. * fix(tgbot): count unreachable recipients in broadcast progress throttle The progress card refresh was keyed on sent+failed, which a 403 does not advance since unreachable chats were split out of the failure count. A streak of unreachable recipients while that sum sat on a multiple of broadcastProgressEvery (0 included, so from the very first recipient) edited the card once per chat, doubling the request rate the send delay is sized for and defeating the throttle. Count processed recipients. * fix(tgbot): key broadcast compositions by admin, not chat After #6604 moved conversation state to the admin (chatUser), the broadcast draft map stayed keyed by chat. Two admins composing in one group then shared a slot: the second admin's message dropped the first admin's draft, whose Send tap answered "went wrong" while only the other draft could go out - the same class #6604 fixed for the add-client wizard. Drafts, album buffers and confirm tokens now live under the admin who ran /broadcast. The router now hands handleBroadcastInput only the admin whose own /broadcast is awaiting input, so its sender re-check and the test that fed it a non-admin message directly (an input no route can deliver) are removed. --------- Co-authored-by: MHSanaei <[email protected]>
  • 71e38367c1 feat(sub): add Incy app-management parameters (#6650) * feat(sub): add Incy app-management parameters The panel already pushes a set of Happ headers, but INCY documents its own lowercase header names and its own value domains, so a Happ-shaped payload gets ignored by the client (per-app mode is bypass|proxy, not on|bypass, and per-app-proxy-enable has no Happ counterpart at all). Add a sibling Incy path that emits exactly the documented headers. Covered, per https://docs.incy.cc/en/app-management/: - profile-description, sort-order, support-email, announce-url, premium-url - banner text/button/URL and the two hex colours - hide-url, hide-check, no-limit-enabled - per-app split tunnelling (enable/mode/list) - TCP fragmentation (enable/length/interval/packets) - UDP noise packets (enable/type/packet/delay) - DoH pre-resolution (enable/domain/IP) Each string setting is tri-state: an empty value omits the header, so an untouched panel never overrides the subscriber's own choice in the app. Values are validated against the documented domains and dropped when they do not match, and non-ASCII text is base64-wrapped the way the docs require for Cyrillic. INCY identifies itself as INCY/<version>/<platform>, which gates the headers behind the same auto-detect switch the Happ path uses. Headers the panel already emits for every client (Profile-Title, Support-Url, Profile-Web-Page-Url, Announce, Profile-Update-Interval, Subscription-Userinfo) and Incy's routing line are left as they are. The Premium API (theme, defaultPingProtocol, fallbackHosts, ...) is a separate encrypted endpoint and stays out of scope here. * fix(sub): keep Incy per-app list entries separate on the wire The Incy settings textarea takes one package per line, as Incy documents for per-app-proxy-list, but the header path ran the value through sanitizeHeaderValue, which deletes CR/LF. "com.google.chrome\norg.telegram.messenger" reached the client as the single bogus package "com.google.chromeorg.telegram.messenger", so per-app split tunnelling silently matched no app. Join comma- or line-separated entries as CSV instead. Also drop three tests that could not fail: TestIncyExcludesHappOnlyHeaders (ApplyIncyHeaders has no path that emits Happ headers, and the non-Happ UA gate is already pinned by TestApplyHappHeaders_Gating) and two UI tests that only asserted updateSetting received the key the JSX passes it. --------- Co-authored-by: DIMFLIX <[email protected]> Co-authored-by: MHSanaei <[email protected]>
  • View comparison for these 30 commits »

12 hours ago

txlyre synced commits to main at txlyre/3x-ui from mirror

  • dcaadd4857 fix(panel): validate sponsor logo name before any file or network use The public /sponsors/logo/:name route only accepted names matching an active sponsor's logo, which was already regex-filtered, but that guard was indirect. Checking sponsorLogoRe on the name itself makes the path/URL safety local and clears CodeQL alerts #113 (go/request-forgery) and #114 (go/path-injection).

20 hours ago

txlyre synced commits to main at txlyre/3x-ui from mirror

  • fd7b3559bc feat(panel): add sponsor slots fed from sponsors.sanaei.dev Monthly sponsor placements need to change without cutting a panel release. Panels now read 3X/sponsors.json from the MHSanaei/sponsors repo (GitHub Pages on sponsors.sanaei.dev) and show active sponsors in four slots: an overview banner, a rotating sidebar card (max three), the login page and a new Sponsors page that also lists open placements. An entry shows only while enable is not false and until is in the future; links must be https and logos are png/webp/jpg by name only. The list is cached for an hour and the last good copy survives upstream failures; logos are proxied through /sponsors/logo/:name with failures cached, so CSP stays 'self' and admin browsers never reach a third party. Admins can hide a slot for 24h. Under XUI_DEBUG the panel reads a sibling ../sponsors/3X checkout so edits can be previewed before push.

1 day ago

txlyre pushed to master at txlyre/libqirt

1 day ago

txlyre pushed to master at txlyre/qic

1 day ago

txlyre pushed to master at txlyre/libqirt

1 day ago

txlyre synced commits to main at txlyre/3x-ui from mirror

  • 89e200ead4 fix(frontend): key geo entries by page position and clear test-suite noise Zod 4: use the `error` param instead of the deprecated `message`. lint:deprecated missed these because tsgolint's no-deprecated does not resolve object-literal properties on a `string | Params` union. Geodata: key geo entry rows by page position. antd deprecates rowKey's index argument, and kind:value repeats within a page because the reader drops domain attributes (22 pairs in geosite_IR.dat, 108 in geosite_RU). Nord/PIA: the "All cities/regions" option used a null value, which antd warns on. Map it through a sentinel at the Select boundary so form state stays null, with tests that fail when the sentinel is not mapped back. Tests: - Run the oxlint guard through node; .bin/oxlint is a sh shim Windows cannot spawn, and the swallowed error left both guard cases vacuous. - Start unit workers with --no-experimental-webstorage; msw's localStorage probe made Node 25+ warn once per forked worker. - Set IS_REACT_ACT_ENVIRONMENT, which RTL never sets with globals: false, and settle the async updates it exposed inside act(). The row-cells memo test now fails when memo is removed. - Disable antd's click wave in Storybook; it re-rendered inside the next story's act() and tripped "not configured to support act". - Assert InboundFormModal's validation log instead of leaking it, and give the rule-form test a well-formed clients/list response.

1 day ago

txlyre synced commits to main at txlyre/3x-ui from mirror

  • a03228c455 ci: update Claude workflow model settings Use Claude Opus 5.5 with high effort for issue analysis and PR reviews.
  • 86302d2f2d chore(deps): update toolchains and dependencies Raise the frontend baseline to Node 26/npm 11 and refresh contributor documentation. Update frontend, documentation-site, and Go dependencies with regenerated lockfiles and module checksums.
  • View comparison for these 2 commits »

1 day ago

txlyre synced and deleted reference dependabot/npm_and_yarn/frontend/vitest/coverage-v8-5.0.1 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/npm_and_yarn/frontend/vitest/browser-playwright-5.0.1 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/npm_and_yarn/frontend/tanstack/react-query-5.103.1 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/npm_and_yarn/frontend/oxlint-tsgolint-7.0.2002 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/npm_and_yarn/frontend/jsdom-30.1.0 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/go_modules/google.golang.org/grpc-1.84.0 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/go_modules/go.uber.org/atomic-1.12.0 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/go_modules/github.com/go-playground/validator/v10-10.30.5 at txlyre/3x-ui from mirror

1 day ago

txlyre synced and deleted reference dependabot/go_modules/github.com/gin-contrib/sessions-1.1.2 at txlyre/3x-ui from mirror

1 day ago

txlyre synced commits to dependabot/npm_and_yarn/frontend/vitest/coverage-v8-5.0.1 at txlyre/3x-ui from mirror

  • 4d2f005fcc chore(deps-dev): bump @vitest/coverage-v8 in /frontend Bumps [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.1/packages/coverage-v8) --- updated-dependencies: - dependency-name: "@vitest/coverage-v8" dependency-version: 5.0.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]>
  • 95f19b192f fix(nodes): stop a restarting panel from reporting itself as down Adding a node fails right after that node's panel restarts. nodes/add probes the node's /panel/api/server/status first, and that endpoint returns whatever the @2s ticker last sampled - nil until the first tick lands, so the master reads a healthy panel as unreachable and rejects it with "Add node (remote returned success=false: )", an error whose message is empty because the node answered success with a null obj. The window is far wider than one tick: GetStatus resolved the public IPv4/IPv6 addresses inline and held s.mu across every lookup, so a box with no IPv6 route spent 3s per service - about 15s of nil status after each restart, and the same stall on a fresh panel's first sample. - status now answers from CurrentStatus, which samples on demand when the ticker has not run yet instead of returning a null obj - the public-IP lookups run in the background and outside s.mu, so a status sample never waits on them - probe tells "no status yet" apart from a genuine success=false, so the master's error says something when it meets an older node
  • 1c0ce80e8e fix(ci): keep a refused Claude credential from reddening a pull request (#6585) * fix(ci): keep a refused Claude credential from reddening a PR An expired subscription ends the claude-code-action step with exit 0, so the classifier that exists for "the API refused this run" never sees it -- its condition is a failed step -- and the final "posted nothing" step reddens the pull request although nothing is wrong with the repository. Verified against five real runs (35159059540, 35184688775, 35185722358, 35186543654, 35187380192): step 8 success, step 10 found no cause, step 11 failure, transcript {"error":"oauth_org_not_allowed"} plus a result entry with api_error_status 403. A usage-limited run carries 429 and a rejected rate_limit_event, and a real review carries is_error false with no status, so the 401/403 test fires on the refused credential alone. * fix(ci): stop a refused credential reddening the issue analysis The same exit-0 refusal reaches this workflow's "posted no reply" check, which fails for the same reason and shows up as seven failed runs in a day. It never attaches to a pull request -- the trigger excludes them -- so this is the same step and the same 401/403 transcript test applied where the refusal lands. Reported only as a warning annotation: nothing was analysed, and there is no comment worth posting about a credential the maintainer has to renew.
  • f8db7f6c29 fix(nodes): say which half of node mTLS failed, and say it as an error (#6565) * fix(nodes): say which half of node mTLS failed, and say it as an error A configured client CA bundle that will not parse produced the same warning as a settings read that failed, and both read as though mTLS were merely unavailable. It is not: the node API silently stops accepting client certificates, callers fall back to a bearer token or lose their only credential, and the one line saying so is a warning at boot. Report it at error level, and distinguish the two causes rather than attributing a storage fault to the operator's certificate bundle. NodeMtlsClientCAPool now tags the parse failure with ErrNodeMtlsTrustBundleInvalid; its message text is unchanged, so anything matching on the existing string still matches. Startup is deliberately left alone. Refusing to boot was considered and rejected: the bundle is one of two equal credentials here, a panel that will not start takes the proxies and the subscription server with it, and bundles written before the stricter validation landed in #6188 are already stored, editable only through the panel that would no longer come up. The tests pin the tag on an unusable bundle and its absence on an unset one; without the tag the first goes red. * test(nodes): drop a duplicate node mTLS trust-bundle test TestNodeMtlsClientCAPoolLeavesUnsetBundleUntagged asserted only that an unset nodeMtlsClientCAPem yields (nil, nil). That path returns before the line the sentinel change touched, so the test was green with and without ErrNodeMtlsTrustBundleInvalid, and TestNodeMtlsClientCAPool already pins the same two assertions on the same fixture. A test that passes either way certifies nothing and then gets cited as coverage for the sentinel. TestNodeMtlsClientCAPoolTagsAnInvalidBundle, which does go red without the sentinel, stays as the regression guard. --------- Co-authored-by: Sanaei <[email protected]>
  • 536f9a6338 fix(tgbot): localize QR caption via I18nBot (#6564) * fix(panel): accept 2FA codes from adjacent TOTP windows CheckUser compared only gotp.Now(), so a code submitted at the end of its 30s window (or with slight client/server clock drift) failed with 'invalid 2fa code', while the immediate retry in the next window succeeded. Accept current +/-1 window, the standard TOTP skew tolerance. Fixes MHSanaei/3x-ui#6535 * fix(panel): share TOTP skew tolerance with VerifyTwoFactorCode Move the +/-1 window helper to internal/util/totp so both 2FA acceptance points use it: login (CheckUser) and disable/rebind plus username/password changes (VerifyTwoFactorCode). Also shrink comments to the 2-line house rule and anchor the unit test mid-window to avoid a step-boundary flake. Addresses review on #6546 (MEDIUM + 2 LOWs). * fix(tgbot): localize QR caption via I18nBot sendClientQRLinks hardcoded English 'QRCode for client <email>:', bypassing I18nBot, so non-English bot languages (e.g. ru-RU) still got English. Add tgbot.answers.qrCodeForClient key with Email param in all 13 locales and route the caption through I18nBot. Fixes MHSanaei/3x-ui#6562 * fix(tgbot): repair locale JSON syntax, harden QR i18n test - Add missing separators so all 13 locale files parse again. - Rewrite the regression test to read the real shipped files (fails on malformed JSON or missing key). - Add TestTgbotLocalesQrKeyValid covering every locale file. * chore(tgbot): drop QR caption tests that cannot catch the bug TestQRCodeForClientLocalizes never calls sendClientQRLinks: it registers two messages in a synthetic bundle and asserts on I18nBot, a passthrough to go-i18n. With the tgbot_client.go line reverted to the hardcoded English caption, both it and TestTgbotLocalesQrKeyValid still pass, so neither certifies the fix. The malformed-locale class they were added for is already pinned twice: the discord package's TestMain loads every translation file through locale.InitLocalizer and panics on invalid JSON, and frontend/src/test/i18n-dead-keys.test.ts parses all 13 locales and checks each carries the en-US key set. Both go red on the #6564 syntax error this PR first shipped. --------- Co-authored-by: sdhfsl <[email protected]> Co-authored-by: Sanaei <[email protected]>
  • View comparison for these 10 commits »

2 days ago

txlyre synced new reference dependabot/npm_and_yarn/frontend/vitest/coverage-v8-5.0.1 to txlyre/3x-ui from mirror

2 days ago

txlyre synced commits to dependabot/npm_and_yarn/frontend/vitest/browser-playwright-5.0.1 at txlyre/3x-ui from mirror

  • 2a0c4723d1 chore(deps-dev): bump @vitest/browser-playwright in /frontend Bumps [@vitest/browser-playwright](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser-playwright) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.1/packages/browser-playwright) --- updated-dependencies: - dependency-name: "@vitest/browser-playwright" dependency-version: 5.0.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]>
  • 95f19b192f fix(nodes): stop a restarting panel from reporting itself as down Adding a node fails right after that node's panel restarts. nodes/add probes the node's /panel/api/server/status first, and that endpoint returns whatever the @2s ticker last sampled - nil until the first tick lands, so the master reads a healthy panel as unreachable and rejects it with "Add node (remote returned success=false: )", an error whose message is empty because the node answered success with a null obj. The window is far wider than one tick: GetStatus resolved the public IPv4/IPv6 addresses inline and held s.mu across every lookup, so a box with no IPv6 route spent 3s per service - about 15s of nil status after each restart, and the same stall on a fresh panel's first sample. - status now answers from CurrentStatus, which samples on demand when the ticker has not run yet instead of returning a null obj - the public-IP lookups run in the background and outside s.mu, so a status sample never waits on them - probe tells "no status yet" apart from a genuine success=false, so the master's error says something when it meets an older node
  • 1c0ce80e8e fix(ci): keep a refused Claude credential from reddening a pull request (#6585) * fix(ci): keep a refused Claude credential from reddening a PR An expired subscription ends the claude-code-action step with exit 0, so the classifier that exists for "the API refused this run" never sees it -- its condition is a failed step -- and the final "posted nothing" step reddens the pull request although nothing is wrong with the repository. Verified against five real runs (35159059540, 35184688775, 35185722358, 35186543654, 35187380192): step 8 success, step 10 found no cause, step 11 failure, transcript {"error":"oauth_org_not_allowed"} plus a result entry with api_error_status 403. A usage-limited run carries 429 and a rejected rate_limit_event, and a real review carries is_error false with no status, so the 401/403 test fires on the refused credential alone. * fix(ci): stop a refused credential reddening the issue analysis The same exit-0 refusal reaches this workflow's "posted no reply" check, which fails for the same reason and shows up as seven failed runs in a day. It never attaches to a pull request -- the trigger excludes them -- so this is the same step and the same 401/403 transcript test applied where the refusal lands. Reported only as a warning annotation: nothing was analysed, and there is no comment worth posting about a credential the maintainer has to renew.
  • f8db7f6c29 fix(nodes): say which half of node mTLS failed, and say it as an error (#6565) * fix(nodes): say which half of node mTLS failed, and say it as an error A configured client CA bundle that will not parse produced the same warning as a settings read that failed, and both read as though mTLS were merely unavailable. It is not: the node API silently stops accepting client certificates, callers fall back to a bearer token or lose their only credential, and the one line saying so is a warning at boot. Report it at error level, and distinguish the two causes rather than attributing a storage fault to the operator's certificate bundle. NodeMtlsClientCAPool now tags the parse failure with ErrNodeMtlsTrustBundleInvalid; its message text is unchanged, so anything matching on the existing string still matches. Startup is deliberately left alone. Refusing to boot was considered and rejected: the bundle is one of two equal credentials here, a panel that will not start takes the proxies and the subscription server with it, and bundles written before the stricter validation landed in #6188 are already stored, editable only through the panel that would no longer come up. The tests pin the tag on an unusable bundle and its absence on an unset one; without the tag the first goes red. * test(nodes): drop a duplicate node mTLS trust-bundle test TestNodeMtlsClientCAPoolLeavesUnsetBundleUntagged asserted only that an unset nodeMtlsClientCAPem yields (nil, nil). That path returns before the line the sentinel change touched, so the test was green with and without ErrNodeMtlsTrustBundleInvalid, and TestNodeMtlsClientCAPool already pins the same two assertions on the same fixture. A test that passes either way certifies nothing and then gets cited as coverage for the sentinel. TestNodeMtlsClientCAPoolTagsAnInvalidBundle, which does go red without the sentinel, stays as the regression guard. --------- Co-authored-by: Sanaei <[email protected]>
  • 536f9a6338 fix(tgbot): localize QR caption via I18nBot (#6564) * fix(panel): accept 2FA codes from adjacent TOTP windows CheckUser compared only gotp.Now(), so a code submitted at the end of its 30s window (or with slight client/server clock drift) failed with 'invalid 2fa code', while the immediate retry in the next window succeeded. Accept current +/-1 window, the standard TOTP skew tolerance. Fixes MHSanaei/3x-ui#6535 * fix(panel): share TOTP skew tolerance with VerifyTwoFactorCode Move the +/-1 window helper to internal/util/totp so both 2FA acceptance points use it: login (CheckUser) and disable/rebind plus username/password changes (VerifyTwoFactorCode). Also shrink comments to the 2-line house rule and anchor the unit test mid-window to avoid a step-boundary flake. Addresses review on #6546 (MEDIUM + 2 LOWs). * fix(tgbot): localize QR caption via I18nBot sendClientQRLinks hardcoded English 'QRCode for client <email>:', bypassing I18nBot, so non-English bot languages (e.g. ru-RU) still got English. Add tgbot.answers.qrCodeForClient key with Email param in all 13 locales and route the caption through I18nBot. Fixes MHSanaei/3x-ui#6562 * fix(tgbot): repair locale JSON syntax, harden QR i18n test - Add missing separators so all 13 locale files parse again. - Rewrite the regression test to read the real shipped files (fails on malformed JSON or missing key). - Add TestTgbotLocalesQrKeyValid covering every locale file. * chore(tgbot): drop QR caption tests that cannot catch the bug TestQRCodeForClientLocalizes never calls sendClientQRLinks: it registers two messages in a synthetic bundle and asserts on I18nBot, a passthrough to go-i18n. With the tgbot_client.go line reverted to the hardcoded English caption, both it and TestTgbotLocalesQrKeyValid still pass, so neither certifies the fix. The malformed-locale class they were added for is already pinned twice: the discord package's TestMain loads every translation file through locale.InitLocalizer and panics on invalid JSON, and frontend/src/test/i18n-dead-keys.test.ts parses all 13 locales and checks each carries the en-US key set. Both go red on the #6564 syntax error this PR first shipped. --------- Co-authored-by: sdhfsl <[email protected]> Co-authored-by: Sanaei <[email protected]>
  • View comparison for these 10 commits »

2 days ago