Skip to content

Enforce a usage limit on invite links - #2141

Closed
joepio wants to merge 2 commits into
developfrom
claude/invite-usage-limit
Closed

joepio wants to merge 2 commits into
developfrom
claude/invite-usage-limit

Conversation

@joepio

@joepio joepio commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Requested by Joep · project thread

Before: An invite link could be used by any number of people, because invites are stateless signed tokens and the server never counted acceptances. The "Permissions & Invites" action opened an old page with its own invite form, separate from the Share dialog.

After: The Share dialog's link invite (self-hosted servers) has a "Limit uses" control. The limit is signed into the token, so a recipient cannot raise it, and the server records which agents accepted and refuses further ones with "This invite has no usages left. Ask for a new one." The invite page shows that message once the link is used up. An agent that already accepted can reopen the link without using a place. The "Permissions & Invites" action now opens the Share dialog (renamed "Share"), and the old Create Invite form is removed; the hosted editor-seat hint moved into the dialog.

Reported by a self-hoster on Discord.

How:

  • Server: max_usages in the signed payload (server/src/invite_token.rs), acceptances in Tree::PluginMeta behind a mutex, checked in server/src/plugins/invite.rs before rights are granted.
  • Client: generateInviteToken(..., maxUsages), new components/Share/UsageLimit.tsx, action opens the dialog through shareDialogState.ts and ShareDialogHost.
  • Docs in docs/src/invitations.md.

Limits: the count is per accepting server; browser-peer invites cannot carry a limit; hosted email invites and the quick-copy link stay unlimited. de, es and fr translations are empty. The /app/share route still exists for deep links (the e2e specs use it) and is now redundant. Playwright e2e was not run; makeDrivePublic and the share-menu test were edited to go through the dialog and are untested. Screenshots (desktop and 390px) are shared in the project thread, not committed.

Tests: Rust (token roundtrip and tamper, limit enforcement, two agents against a one-use invite), vitest in browser/lib and the Share components.

Invites are stateless signed tokens, so the limit never had anything to
count against. Put an optional usage limit (invite/usagesLeft) in the signed
payload, so it cannot be raised, and record the agents that accepted a token
on the server. Reject further agents with 'This invite has no usages left';
an agent that already accepted may open the link again for free. The invite
preview reports the places left. The Permissions & Invites form gets a
'Limit how many people can use this link' option. Browser-peer invites never
reach a server and refuse a limit.
@joepio joepio self-assigned this Oct 8, 2026
…ion opens it

The Share dialog's open-source invite link gets a compact "Limit uses"
control signed through the existing maxUsages plumbing. The resource
action now opens the dialog (via a module-level host, like the search
overlay) instead of the old Permissions & Invites page, whose Create
Invite form is removed. The editor-seat hint moves into the dialog.
@joepio
joepio force-pushed the claude/invite-usage-limit branch from f202698 to bf01271 Compare October 8, 2026 09:27
joepio added a commit that referenced this pull request Oct 8, 2026
Combines #2123, #2127, #2133, #2134, #2135, #2136, #2138, #2140, #2141, #2142, #2143, #2147, #2149, #2132, #2121, #2129, #2146 and #1870. Includes fixes for the combination: Dagger mount for the form validation cases, drive mapping list without the flush sentinel, web_time in search, sidebar resize test at the touch bar height.

joepio commented Oct 8, 2026

Copy link
Copy Markdown
Member Author

Landed on develop through the batch #2153 (d102056), with this PR's head unchanged. Closing as merged.


Generated by Claude Code

@joepio joepio closed this Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant