Commit graph

37 commits

Author SHA1 Message Date
0eeb3c351f feat(security): rate-limit auth/login + auth/verify 2026-04-27 19:16:32 +01:00
8e76ce9366 refactor(launch): collapse helcim-pay duplication and use setAuthCookie helper
Some checks failed
Test / vitest (push) Successful in 11m49s
Test / playwright (push) Failing after 9m43s
Test / visual (push) Failing after 9m24s
Test / Notify on failure (push) Successful in 2s
Follow-up to 51230e5. /simplify review surfaced residual duplication
and a timer leak.

- useHelcimPay: extract _initializeTicket(metadata, errorPrefix) to
  collapse initializeTicketPayment + initializeSeriesTicketPayment
  (95% identical bodies). Drop the dead `amount` arg from initialize-
  TicketPayment — server re-derives ticket amounts in initialize-
  payment.post.js and never reads body.amount for ticket types.
  Capture timer ids and clearTimeout on resolve/reject so the 10-min
  payment timer and 5-second observer timer stop leaking after every
  payment.
- EventTicketPurchase: caller updated for the dropped arg.
- verify.post.js: replace inline jwt.sign + setCookie block with the
  setAuthCookie(event, member) helper. verify was the last hand-rolled
  caller after the helper was extracted in 208638e.
- LAUNCH_READINESS: add simplify-pass-followups bullet pointing to the
  six deferred items in docs/TODO.md.

Tests: 758 passing, 2 skipped, 0 failing.
2026-04-25 22:13:24 +01:00
51230e5151 refactor(launch): simplify launch-readiness fixes
Follow-up to 208638e. Code review surfaced a few real issues; this
commit addresses them.

- login.post.js now uses the new sendMagicLink util instead of
  duplicating the jti/jwt/Resend/logActivity logic. Reduces 60 lines.
- sendMagicLink accepts an optional pre-loaded Member doc, skipping
  the redundant findOne when the caller already has one. customer.post.js
  passes the just-created/upgraded member, dropping signup from 3
  Mongo round-trips to 1 (lookup is gone; jti burn remains).
- sendMagicLink now lowercases the email defensively so callers don't
  have to remember.
- rateLimit.js: replaced an effectively-dead eviction line with a
  probabilistic sweep (~1% of calls scan and evict keys whose newest
  entry has aged out). Caps unbounded Map growth under random-key
  spraying.
- reconcile-payments.post.js: 401/403/404 from Helcim now bails out
  immediately instead of burning all 3 retry attempts; dry-run
  summary filters via the same RECONCILABLE_STATUSES set as apply
  mode so counts match.
- Deleted WHAT-comments and section banners per CLAUDE.md no-comment
  rule. Kept genuine WHY-comments (validateBeforeSave rationale,
  amount-IGNORED-for-tickets, sendConfirmation deliberately-omitted).

Tests: 758/760 passing (unchanged).
2026-04-25 19:34:16 +01:00
208638e374 feat(launch): security and correctness fixes for 2026-05-01 launch
Day-of-launch deep-dive audit and remediation. 11 issues fixed across
security, correctness, and reliability. Tests: 698 → 758 passing
(+60), 0 failing, 2 skipped.

CRITICAL (security)

Fix #1 — HELCIM_API_TOKEN removed from runtimeConfig.public; dead
useHelcim.js deleted. Production token MUST BE ROTATED post-deploy
(was previously exposed in window.__NUXT__ payload).

Fix #2 — /api/helcim/customer gated with origin check + per-IP/email
rate limit + magic-link email verification (replaces unauthenticated
setAuthCookie). Adds payment-bridge token for paid-tier signup so
users can complete Helcim checkout before email verify. New utils:
server/utils/{magicLink,rateLimit}.js. UX: signup success copy now
prompts user to check email.

Fix #3 — /api/events/[id]/payment deleted (dead code with unauth
member-spoof bypass — processHelcimPayment was a permanent stub).
Removes processHelcimPayment export and eventPaymentSchema.

Fix #4 — /api/helcim/initialize-payment re-derives ticket amount
server-side via calculateTicketPrice and calculateSeriesTicketPrice.
Adds new series_ticket metadata type (was being shoved through
event_ticket with seriesId in metadata.eventId).

Fix #5 — /api/helcim/customer upgrades existing status:guest members
in place rather than rejecting with 409. Lowercases email at lookup;
preserves _id so prior event registrations stay linked.

HIGH (correctness / reliability)

Fix #6 — Daily reconciliation cron via Netlify scheduled function
(@daily). New: netlify.toml, netlify/functions/reconcile-payments.mjs,
server/api/internal/reconcile-payments.post.js. Shared-secret auth
via NUXT_RECONCILE_TOKEN env var. Inline 3-retry exponential backoff
on Helcim transactions API.

Fix #7 — validateBeforeSave: false on event subdoc saves (waitlist
endpoints) to dodge legacy location validators.

Fix #8 — /api/series/[id]/tickets/purchase always upserts a guest
Member when caller is unauthenticated, mirrors event-ticket flow
byte-for-byte. SeriesPassPurchase.vue adds guest-account hint and
client auth refresh on signedIn:true response.

Fix #9 — /api/members/cancel-subscription leaves status active per
ratified bylaws (was pending_payment). Adds lastCancelledAt audit
field on Member model. Indirectly fixes false-positive
detectStuckPendingPayment admin alert for cancelled members.

Fix #10 — /api/auth/verify uses validateBody with strict() Zod schema
(verifyMagicLinkSchema, max 2000 chars).

Fix #11 — 8 vitest cases for cancel-subscription handler (was
uncovered).

Specs and audit at docs/superpowers/specs/2026-04-25-fix-*.md and
docs/superpowers/plans/2026-04-25-launch-readiness-fixes.md.
LAUNCH_READINESS.md updated with new test count, 3 deploy-time
tasks (rotate Helcim token, set NUXT_RECONCILE_TOKEN, verify
Netlify scheduled function), and Fixed-2026-04-25 fix log.
2026-04-25 18:42:36 +01:00
7704557f16 merge: catch up with feature/helcim-plan-consolidation base
# Conflicts:
#	server/api/auth/member.get.js
#	server/api/members/update-contribution.post.js
#	tests/server/api/update-contribution.test.js
2026-04-19 21:33:40 +01:00
57f5152be4 feat(server): rename contributionTier → contributionAmount in routes + utils 2026-04-19 18:44:29 +01:00
5d6fcdd78d feat(account): show next payment date with lazy Helcim refresh
Persist nextBillingDate on subscription create/update; unset on
cancel or downgrade to free. Account page displays the cached
date and lazily refreshes from Helcim when the cached value is
within 24h of now (or missing).
2026-04-19 18:32:04 +01:00
0ca38e5588 fix(auth): expose helcimCustomerId on /api/auth/member
The member account page gates the Helcim customer portal link on
`memberData.helcimCustomerId`, but this endpoint (the source for
`useAuth().memberData`) omitted the field, so the link hid for every
member regardless of Helcim enrollment. Add the field to the response.
2026-04-19 13:04:46 +01:00
fb337a4277 feat(account): display cadence and annual pricing in tier selector 2026-04-18 18:08:10 +01:00
2394248d53 Updates
Some checks failed
Test / vitest (push) Failing after 6m9s
Test / visual (push) Has been skipped
Test / playwright (push) Has been skipped
Test / Notify on failure (push) Successful in 2s
2026-04-15 17:45:09 +01:00
091ec58073 rename communityEcology → board across backend
Model, schemas, API routes, activity log, and all server handlers
updated. Old ecology/ and community-ecology routes removed, new
board/ routes added. Tests updated and new board-suggestions tests
written (10 cases).
2026-04-14 12:00:15 +01:00
c6b970a621 Design token updates.
Some checks failed
Test / vitest (push) Successful in 10m47s
Test / playwright (push) Failing after 9m11s
Test / visual (push) Failing after 9m11s
Test / Notify on failure (push) Successful in 2s
2026-04-11 23:24:38 +01:00
0b3896d984 refactor(community): rename Community Connections → Community Ecology
Some checks failed
Test / vitest (push) Successful in 11m42s
Test / playwright (push) Failing after 9m27s
Test / visual (push) Failing after 9m53s
Test / Notify on failure (push) Successful in 2s
Simplify the feature to pure discovery (filter by topic, see matching
members, copy Slack handle). Drop the connection request/confirm flow
entirely — Connection model, 7 API endpoints, useConnections composable,
and TagInput component deleted.

- Rename communityConnections → communityEcology in schema, API, pages
- Delete legacy fields: offering, lookingFor, peerSupport
- New /ecology page, /api/ecology/suggestions, community-ecology.patch
- Nav: "Connections" → "Ecology", remove pending-count badge
- Fix auth/member.get.js missing craftTags + communityEcology
- Add community_ecology_updated activity log type
- Expose slackHandle conditionally when offerPeerSupport is true
- Add migration script at scripts/migrate-to-ecology.js (run before deploy)
2026-04-09 09:07:15 +01:00
0ae18f495e Tests, UX improvements. 2026-04-05 14:25:29 +01:00
d31b5b4dac fix: use private helcimApiToken for all server-side Helcim API calls 2026-04-04 13:37:34 +01:00
e592b962ec fix: replace member.save() with findByIdAndUpdate in login.post.js 2026-04-04 13:22:36 +01:00
ee438f5c60 chore: remove working copies and superseded verify.get.js 2026-04-04 12:41:33 +01:00
d4d9629d83 fix: remove redundant connectDB in verify (requireAuth handles it) 2026-04-04 12:25:25 +01:00
79c712a9e9 fix: replace member.save() with atomic update in verify 2026-04-04 12:24:52 +01:00
707ff7b13a fix: remove redundant connectDB in logout (requireAuth handles it) 2026-04-04 12:24:24 +01:00
ab2532dee8 fix: replace member.save() with atomic update in logout 2026-04-04 12:23:01 +01:00
c785a23910 Redirect regular members to coming-soon page after magic link login
Instead of sending members directly to the wiki (where they hit
Outline's login page and have to click again), land them on the
coming-soon page which shows a welcome message and wiki link.
2026-03-19 13:02:12 +00:00
772f57c2b2 Route login redirect by role: admins to /admin, everyone else to wiki 2026-03-19 10:48:35 +00:00
c0dcfac173 Redirect invite logins to wiki, regular logins to /members
Invite tokens now include a redirect claim so the verify endpoint
can distinguish them from regular login tokens. Only invite links
redirect to wiki.ghostguild.org; normal logins go to /members.
2026-03-19 10:48:00 +00:00
27c07cd3e9 Send invite emails as HTML with clickable button, redirect login to wiki
Invite emails now include both plain text and HTML versions. The
{loginLink} placeholder renders as a styled button in HTML email
clients. Other URLs in the template are auto-linked. The auth verify
endpoint redirects to wiki.ghostguild.org instead of /members.
2026-03-19 10:41:21 +00:00
c3c8b6bcd4 Refactor email templates to use plain text format and update sender addresses
- Simplified the magic link email format to plain text for better compatibility.
- Updated the welcome email to use plain text and changed the sender address to match the domain.
- Enhanced event registration email format to plain text, removing HTML styling for a cleaner approach.
2026-03-05 18:40:37 +00:00
025c1a180f Add Zod validation to all API endpoints and remove debug test route
Adds schema-based input validation across helcim, events, members,
series, admin, and updates API endpoints. Removes the peer-support
debug test endpoint. Adds validation test coverage.
2026-03-01 17:04:26 +00:00
b7279f57d1 Add Zod validation, fix mass assignment, remove test endpoints and dead code
- Add centralized Zod schemas (server/utils/schemas.js) and validateBody
  utility for all API endpoints
- Fix critical mass assignment in member creation: raw body no longer
  passed to new Member(), only validated fields (email, name, circle,
  contributionTier) are accepted
- Apply Zod validation to login, profile patch, event registration,
  updates, verify-payment, and admin event creation endpoints
- Fix logout cookie flags to match login (httpOnly: true, secure
  conditional on NODE_ENV)
- Delete unauthenticated test/debug endpoints (test-connection,
  test-subscription, test-bot)
- Remove sensitive console.log statements from Helcim and member
  endpoints
- Remove unused bcryptjs dependency
- Add 10MB file size limit on image uploads
- Use runtime config for JWT secret across all endpoints
- Add 38 validation tests (117 total, all passing)
2026-03-01 14:02:46 +00:00
26c300c357 Implement OWASP ASVS L1 security remediation (Phases 0-2)
Auth: Add requireAuth/requireAdmin guards with JWT cookie verification,
member status checks (suspended/cancelled = 403), and admin role
enforcement. Apply to all admin, upload, and payment endpoints. Add
role field to Member model.

CSRF: Double-submit cookie middleware with client plugin. Exempt
webhook and magic-link verify routes.

Headers: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection,
Referrer-Policy, Permissions-Policy on all responses. HSTS and CSP
(Helcim/Cloudinary/Plausible sources) in production only.

Rate limiting: Auth 5/5min, payment 10/min, upload 10/min, general
100/min via rate-limiter-flexible, keyed by client IP.

XSS: DOMPurify sanitization on marked() output with tag/attr
allowlists. escapeHtml() utility for email template interpolation.

Anti-enumeration: Login returns identical response for existing and
non-existing emails. Remove 404 handling from login UI components.

Mass assignment: Remove helcimCustomerId from profile allowedFields.

Session: 7-day token expiry, refresh endpoint, httpOnly+secure cookies.

Environment: Validate required secrets on startup via server plugin.
Remove JWT_SECRET hardcoded fallback.
2026-03-01 12:53:18 +00:00
970b185151 Updates to profile 2025-10-06 14:52:03 +01:00
1b8dacf92a Add peer support functionality and UI 2025-10-06 11:29:47 +01:00
2b55ca4104 Adding features 2025-10-05 16:15:09 +01:00
600fef2b7c Enhance authentication flow: Add authentication-based buttons in AppNavigation for logged-in users, improve member status checks in useAuth, and update join page to automatically redirect to the dashboard after registration. Adjust cookie settings for better development experience. 2025-09-03 16:55:01 +01:00
2ca290d6e0 Implement multi-step registration process: Add step indicators, error handling, and payment processing for membership registration. Enhance form validation and user feedback with success and error messages. Refactor state management for improved clarity and maintainability. 2025-09-03 14:47:13 +01:00
e4a0a9ab0f Enhance application structure: Add runtime configuration for environment variables, integrate new dependencies for Cloudinary and UI components, and refactor member management features including improved forms and member dashboard. Update styles and layout for better user experience. 2025-08-27 16:49:51 +01:00
6e7e27ac4e Enhance UI and functionality: Update main page layout, add contribution options in join form, and improve member dashboard display. Refactor API endpoints for member creation and login. 2025-08-26 18:21:52 +01:00
826517a798 Initial commit 2025-08-26 14:17:16 +01:00