Pds: invite codes are only presence-checked — no store, validation, single-use semantics, or admin endpoints #36
Labels
No labels
breaking-change
bug
documentation
duplicate
enhancement
good first issue
help wanted
performance
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/ATProto.NET#36
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
With
PdsOptions.OpenRegistration = false,PdsService.CreateAccountAsynconly checks that the invite code is non-empty (PdsService.cs:52-53) — any string passes:So "invite codes are required" is not actually enforceable with the package alone. There is no storage, validation, consumption (single-use semantics), or admin surface for codes.
While building Updraft's PDS container I had to implement all of this app-side:
InviteCodestable + service with atomic claim/confirm/release (single-UPDATE claim so concurrent signups can't double-spend a code)POST /xrpc/com.atproto.server.createAccount(because the SDK's mapped endpoint would accept any non-empty string)com.atproto.server.createInviteCode,com.atproto.admin.getInviteCodes,com.atproto.admin.disableInviteCodeswith Basic admin authSuggestion: an
IInviteCodeStoreabstraction (with an in-memory default) thatCreateAccountAsyncconsults + consumes whenOpenRegistration == false, plus optional mapping of the standard invite admin XRPC endpoints (they exist in the com.atproto lexicons) guarded by a configurable admin credential. Happy to share our implementation as a starting point: https://git.grandiras.net/Grandiras/Updraft (src/Updraft.Pds).🤖 On it — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
Implemented invite codes as a real feature in
ATProtoNet.Pds. Branch:claude/issue-36.What changed
IInviteCodeStore(new) — the storage seam, withPdsInviteCode/PdsInviteCodeUse. Redemption is the three-step protocol you described:TryClaimAsyncatomically reserves one use —falseif the code is unknown, disabled, or exhaustedConfirmClaimAsyncrecords the redeeming DID once the account existsReleaseClaimAsyncreturns the reservation if creation fails afterwards (taken handle, store error), leaving the code usableInMemoryInviteCodeStoreis the default (development-grade — codes are lost on restart). For production,AddAtProtoPds<TAccountStore, TRepoStore, TInviteCodeStore>()registers your own; the docs include the single-UPDATESQL sketch soTryClaimAsyncstays atomic.PdsService.CreateAccountAsyncnow claims → creates → confirms whenOpenRegistration == false. PlusCreateInviteCodeAsync,CreateInviteCodesAsync,GetInviteCodesAsync,GetAccountInviteCodesAsync,DisableInviteCodesAsync. Generated codes follow the reference PDS shape (my-pds-example-com-a2b3c-d4e5f), fromRandomNumberGenerator.Five new mapped endpoints, all in
PdsEndpointNamessoExclude/Only/Configurework on them:com.atproto.server.createInviteCode,createInviteCodes,getAccountInviteCodes(Bearer, caller's own codes),com.atproto.admin.getInviteCodes(sort=recent|usage,limit,cursor),com.atproto.admin.disableInviteCodes(by code and/or account).Admin auth —
PdsOptions.AdminPassword/AdminUsername(defaultadmin), HTTP Basic, fixed-time compare. It fails closed: unconfigured means every admin request gets401, not open access.Two decisions worth flagging
PdsServicegained a fifth constructor parameter (IInviteCodeStore? = null) — source-compatible, binary-breaking. Filed underBreaking changesin the CHANGELOG.OpenRegistration = trueis unaffected.Updraft can now drop the shadowing middleware and the app-side table; if you'd rather keep your own admin surface,
Excludethe four admin endpoints and delegate toPdsService.Verified
Installed the .NET 10 SDK in the container (none was present).
dotnet buildacross the solution: 0 errors, no new warnings fromATProtoNet.Pds.dotnet test tests/ATProtoNet.Tests/: 1092 passed, 0 failed, including 60 new tests — single/multi-use redemption, disabled and unknown codes, release-on-failure, 20 concurrent sign-ups against a 3-use code redeeming exactly 3 times, admin auth rejection paths (no credential, wrong password, wrong username, Bearer-instead-of-Basic, malformed base64, unconfigured password), and admin listing/paging/disable over HTTP.CHANGELOG.mdupdated underAdded,Breaking changes, andSecurity;docs/pds.mdgains an "Invite Codes" section.→ Opened PR: #64
⏱ 11m 52s · 65 turns · 📜 Full session transcript
(reply recovered from the transcript — the posting step in runs before v12.3 was broken by a shell-quoting bug)