Commit Graph
9 Commits
Author SHA1 Message Date
yusufipek 4c0b18e5e4 feat(marketing): say no card where the trial is actually claimed
Three places still carried the old promise. The register form, which is where
the CTA lands and where the trial is granted, said nothing about it at all, so
the landing page's claim had to be taken on faith across a page load. The
comparison profile summary still described the trial without mentioning the
card. And the CtaLink comment quoted a button label that no longer exists.

The hero and closing CTAs now read 'Open dashboard' for a signed-in visitor.
That button already pointed at /dashboard for them, and offering a free trial
to someone who is mid-subscription reads as a bug. The pricing card keeps the
short label because it sits directly under 'No credit card' and the card
narrows to about 230px at the md breakpoint, where the long label would wrap
out of a fixed-height button.
2026-08-18 09:23:21 +03:00
yusufipk b1aed03fca fix(invitations): throttle unauthenticated invitation lookups and harden redirects
The invitation preview surfaces (/invitations/accept and /register?invitationToken=) are the
only unauthenticated reads of invitation data, and each render costs two database queries.
They are now rate limited before the lookup can touch the database: a generous per-IP bucket
that bounds enumeration across tokens, plus a tight per-IP+token bucket that stops repeated
probing of a single invitation. Tokens are hashed before they reach the rate_limits table.

A throttled lookup says so ("we couldn't check this invitation right now") instead of claiming
the invitation is invalid, and signed-in acceptance is not gated by it.

The callback sanitizer also checked only the origin, which is not enough: an attacker can
smuggle a host into the path of an otherwise same-origin URL — new URL('https://app/​/evil.com')
keeps our origin but yields a pathname of //evil.com, which navigation sinks resolve as
protocol-relative and follow off-site. Paths are now required to be rooted at a single slash,
and the login redirect re-checks at the sink.

getClientIp is split so server components that only have `await headers()` resolve the client
IP through the same trusted-proxy logic as route handlers.
2026-07-25 19:39:16 +07:00
yusufipk 9c75ce91e1 feat(invitations): guide invited users without an account through sign-up
Clicking an invitation link while signed out dropped the visitor on a bare login form,
even though most invitees have no account yet and nothing on screen told them to create one.

Signed-out visitors now get the invitation itself: who invited them, which workspace/project,
which role, and which address it was sent to. The primary call to action follows whether an
account already exists for that address — "Create your account" when it does not, "Sign in to
accept" when it does.

The sign-up path carries the invitation forward, so a new account lands back on the invitation
and from there on the shared workspace/project instead of the onboarding wizard:
- the register link passes invitationToken, the invited email and a callbackUrl
- the register form locks the email to the invited address and shows what is being joined
- the verification email round-trips the destination through a sanitized `next` parameter
- login and verify-email keep the pending destination in their sign-in links

Signing in with a different address than the one invited now explains the mismatch instead of
silently redirecting to the dashboard.

Callback sanitization moves to lib/safe-redirect.ts so login, register, verify-email and the
verification route share one open-redirect guard.
2026-07-25 18:44:02 +07:00
yusufipk 56fb7403cf fix: resolve CI lint and formatting failures.
Replace internal anchor tags with Next.js Link components and format the marketing comparison route page.
2026-06-14 16:42:27 +02:00
Enes Köksal 3cfea40fbd refactor: eslint and prettier conflict will be resolved and formatted 2026-04-23 17:05:43 +03:00
Yusuf İpek faa902a604 feat(auth): implement email verification process with resend functionality and update registration flow 2026-04-11 00:17:09 +03:00
Yusuf İpek f622752233 feat(auth): enhance registration page with OAuth support for Google and GitHub 2026-04-10 22:50:02 +03:00
Yusuf İpek 20897ab418 feat(privacy, refund, terms): add Privacy Policy, Refund Policy, and Terms of Service pages with navigation links 2026-04-10 22:33:23 +03:00
Yusuf İpek b1b1715578 Refactor registration and dashboard features to support invite codes and Bunny uploads
- Moved registration logic to a new client component for better separation of concerns.
- Integrated invite code requirement based on feature flags in the registration process.
- Enhanced dashboard functionality to conditionally enable Bunny uploads based on feature flags.
- Updated various components and API routes to check for Bunny uploads and Stripe billing feature flags.
- Added new feature flag utilities for managing feature toggles in the application.
2026-04-08 18:46:12 +03:00