Skip to content

v3.3.1

Choose a tag to compare

@GkhanKINAY GkhanKINAY released this 09 Aug 02:35
· 96 commits to main since this release
d53680d

The last release before launch. Three fixes, one of them a security hole.

Security

A session cookie could mint a free unlimited organization. All three /public/v1/… enterprise routes took the caller's Authorization header and verified it against JWT_SECRET, which is the same secret that signs ordinary login cookies. Any registered user could therefore call them and create an organization on a lifetime AGENCY subscription. They now verify against ENTERPRISE_SECRET, and refuse outright when that variable is unset.

Payments

The payment path could cancel the subscription it just sold. checkValidCard attempted an off-session $1 authorization on every first customer.subscription.created, and cancelled the subscription and detached the card whenever it did not come back requires_capture — including on any thrown error. In an SCA region that is the expected outcome for a 3DS card, not an exception. Stripe Checkout already validates the card, so the check now logs and returns true.

Alongside it, in the same path: statuses that are not entitlements (canceled, unpaid, incomplete_expired, paused) no longer write a paid tier; products.list pages to 100 so the catalog cannot outgrow the default page of 10; uniqueId is restored to plan-change metadata so both webhooks can find the row; invoice.payment_failed is typed info rather than success, so a customer who turned success mail off still hears about a failed renewal; an unsigned request to /stripe returns 400 instead of a 500 with a stack trace; and the post-checkout screen stops polling after 60 tries and offers a way out instead of holding the customer in an uncloseable overlay.

Correctness

Config-off paths tell the truth. Password reset and team invites checked their expiry window without first checking the field existed, so a null compared as "not yet expired". The AI availability rule lived in three places and disagreed with itself; it is now one exported function. Date formatting read the browser at module load, which does not exist during SSR — it reads the resolved snapshot instead. post.workflow.v1.0.6 replaces v1.0.5's generic-error branch, which fell through and re-ran postSocial after a failure that had already been handled.

Full diff: v3.3.0...v3.3.1