Patch 3.13.1 - #4311
Merged
Merged
Conversation
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.0.1 to 10.4.0. - [Release notes](https://github.com/beaugunderson/ip-address/releases) - [Commits](beaugunderson/ip-address@v10.0.1...v10.4.0) --- updated-dependencies: - dependency-name: ip-address dependency-version: 10.4.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.2 to 3.1.5. - [Release notes](https://github.com/fastify/fast-uri/releases) - [Commits](fastify/fast-uri@v3.1.2...v3.1.5) --- updated-dependencies: - dependency-name: fast-uri dependency-version: 3.1.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
Backport 3.13.0
POST /login/dashboard/ticket mints a 30-second signed ticket naming the caller's own user and, optionally, one farm they are an Active member of. The Analytics Dashboard trades the ticket server-to-server for that identity, so no identity travels in a browser-visible URL. Each ticket carries a randomUUID jti for the replay table added in a follow-up. JWT_DASHBOARD_SECRET is a sixth signing secret, so a leaked ticket can never be presented as a login token. return_to must match an entry of DASHBOARD_ALLOWED_RETURN_TO exactly. Without that check, an attacker could send a user to a sign-in URL bearing their own return address and be handed a valid ticket. Empty entries are filtered out of the parsed list, so an unset or blank variable rejects every address rather than matching an empty return_to. checkJwt is attached to the route directly, because the login router is mounted before the global checkJwt in server.ts. user_id is read from req.auth only; a user_id in the request body is ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gle-use-dashboard-ticket-issued-only-to-an-allowlisted-return-address LF-5416 Add a 30-second single-use dashboard ticket endpoint
POST /login/dashboard/exchange trades the 30-second ticket minted by
/login/dashboard/ticket for the user's identity and their current farm
memberships. The Analytics Dashboard's server calls it from its own
/auth/finish handler; until now that call received a 404 and the user was
told LiteFarm could not be reached.
The new dashboard_ticket_use table is what makes the ticket single-use. Its
primary key is the ticket's jti, and the insert is the claim:
onConflict('jti').ignore().returning('jti') reports whether this request was
the one that inserted, so two concurrent exchanges cannot both succeed. The
transaction holds that insert and the five-minute prune and nothing else, so
a later rejection cannot roll the claim back and release the ticket.
The farm list is read live and filtered to Active memberships on farms that
are not deleted, because the Dashboard's own database is a nightly copy. The
farm_id the ticket names is checked against that list before it is returned:
the Dashboard writes that field straight into its session as the active farm
without comparing it to the farms it was sent.
The route carries no checkJwt. Express mounts /login before the global
checkJwt in server.ts, so nothing under that path reaches the middleware, and
the caller is a server holding no LiteFarm token.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
'claimed' felt ambiguous as it could have also referred to the ticket state; what it is actually tracking is the outcome of *this* request
…at-exchanges-a-dashboard-ticket-for-identity-and-live-farm-membership LF-5417 Add the dashboard ticket exchange endpoint
getReturnToFromSearch reads the return_to query parameter from a location search string. buildDashboardTicketUrl attaches the ticket with URLSearchParams, so a return address that already carries a query string still works. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The slice holds the return address captured on arrival plus a flag for the request being in flight. handOffToDashboardIfRequested is the single place that calls POST /login/dashboard/ticket: it reports false when no return address is stored, clears the address on success and on failure, and navigates to the address the API returned rather than the stored copy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gle sign-in customLoginWithPasswordSaga, customCreateUserSaga and loginWithGoogleSaga each ask handOffToDashboardIfRequested before navigating. It answers false unless the user arrived from the Dashboard with a return address, and a sign-in without one reaches its ordinary destination. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…live Access tokens last seven days, so a user sent over from the Dashboard usually still has a LiteFarm session and would otherwise land on the Home page. useDashboardHandoff reads the return address during render, because CustomSignUp is a child of Routes and replaces the location with one that carries no search string. On mount it stores the value or null and starts the hand-off when a token is present; Routes renders a Spinner in place of the route tree until the browser leaves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The endpoint moves to store/api/dashboardTicketApi.ts as a mutation, where new endpoints belong, and prepareHeaders supplies the Authorization header. handOffToDashboardIfRequested becomes a plain async function in containers/dashboardTicketHandoff.ts; yield call accepts it unchanged, so the three sign-in sagas keep the same two lines and the watcher and its action are no longer needed. request.reset() drops the mutation result once the ticket has been read. The whole store is persisted to localStorage, so without it the ticket would be written to disk. Starting the endpoint needs a cast to the thunk dispatch signature, because store.ts annotates its middleware array as Middleware[] and that reduces store.dispatch to Dispatch<AnyAction>. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Set X-Forwarded headers and remove incorrect ones
* access req.ip for client IP logging
401 is returned from this endpoint only from checkJwt, before the controller runs. Note that an invalid return_to is a 400
…n ticket minting sounding like an error on redirect (which was never even run)
…e-dashboard-after-password-new-account-and-google-sign-in LF-5418 Send the user to the dashboard after password new account and google sign in
The include glob was src/tests/**/*.test.js?(x), so a .ts or .tsx test file was collected by nothing and passed by not running. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
id_token in localStorage and user_id in the persisted store are written separately and can disagree. A token with no identity is not a usable session, and the token is cleared. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
isAuthenticated() reports only that a token exists. Every farm selector filters on user_id, so a token-only session rendered the signed-in tree with no farms and no request that could 401. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Concern is the a second tab now getting into the opposite broken state -- Redux user_id but no id_token
* set gzip_proxied to any and add image/svg+xml to gzip_types
LF-4982: Improve nginx.conf
…second-tab-sits-on-the-sign-on-screen-locks-the-user-on-the-welcome-screen-with-no-way-back LF-5443 Signing in while a second tab sits on the sign on screen locks the user on the welcome screen with no way back
…address-10.4.0 Bump ip-address from 10.0.1 to 10.4.0
…kages/api/fast-uri-3.1.5 Bump fast-uri from 3.1.2 to 3.1.5 in /packages/api
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
…ntegration_webapp_locales New Crowdin translations webapp_locales
Update version to 3.13.1
SayakaOno
marked this pull request as ready for review
August 13, 2026 17:54
SayakaOno
requested review from
den4ik1203 and
kathyavini
and removed request for
a team
August 13, 2026 17:54
den4ik1203
approved these changes
Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://lite-farm.atlassian.net/projects/LF/versions/10431/tab/release-report-all-issues