Skip to content

fix: server-validate restore receipts and scope form cache by userId#708

Merged
RUKAYAT-CODER merged 2 commits into
rinafcode:mainfrom
authenticeasy-sys:fix/615-616-payment-restore-validation-and-form-cache-user-scope
Jun 27, 2026
Merged

fix: server-validate restore receipts and scope form cache by userId#708
RUKAYAT-CODER merged 2 commits into
rinafcode:mainfrom
authenticeasy-sys:fix/615-616-payment-restore-validation-and-form-cache-user-scope

Conversation

@authenticeasy-sys

Copy link
Copy Markdown
Contributor

Summary

Fixes two privacy/security bugs identified in issues #615 and #616.


Fix #615 — restorePurchases validates receipts server-side before updating state

Problem: restorePurchases() called RNIap.getAvailablePurchases() and mapped every result directly to PurchaseRecord, meaning a stale, cancelled, or refunded purchase could grant premium access.

Changes to src/services/mobilePayments.ts:

  • Each restored purchase is POST'd to /payments/validate-receipt before state update.
  • Only purchases with valid: true are added to the restored list and finished via finishTransaction.
  • Invalid receipts are logged with appLogger.infoSync and skipped.
  • _setTier is called for the most-recently-dated valid subscription.
  • Fixed all stale log.error calls → appLogger.errorSync.

Fix #616 — useFormCache cache key is user-scoped

Problem: All users on the same device shared form data under a single storage key (@teachlink/form-cache/v1), causing privacy leakage between users.

Changes to src/services/formCache.ts:

  • Added getFormCacheStorageKey(userId) returning @teachlink/form-cache/${userId}/v1.
  • All storage functions (loadFormCache, saveFormCache, getCachedFieldValues, cacheFormValues, setCachedFieldValue, clearFormCache) now take storageKey as their first parameter.

Changes to src/hooks/useFormCache.ts:

  • Reads userId from useAppStore via selector.
  • Derives storageKey with useMemo so it recomputes when the user changes.
  • Cache reloads automatically on user switch (logout → login as different user).

Tests

  • src/__tests__/services/mobilePayments.test.ts (new): 4 tests verifying valid/invalid receipt filtering, finishTransaction only called for valid, and tier updated after restore.
  • src/__tests__/services/formCache.test.ts (new): 6 tests verifying distinct user keys, correct read/write scoping, and that one user's data cannot bleed into another.
  • tests/services/formCache.test.ts (updated): All assertions migrated to use the new storageKey parameter.
  • tests/hooks/useFormCache.test.ts (updated): Store mocked to provide userId; clearCache assertion updated to expect the user-scoped key.

Closes #615
Closes #616

…cache by userId (rinafcode#616)

Issue rinafcode#615 – restorePurchases server validation
- Each restored purchase is now POST'd to /payments/validate before
  updating subscription state.
- Only purchases with validated: true update state; invalid receipts are
  logged and skipped.
- _setTier is called for the most-recently-validated restored subscription.
- Fixed stale log.error calls -> appLogger.errorSync throughout the service.

Issue rinafcode#616 – useFormCache user-scoped cache key
- Added getFormCacheStorageKey(userId) which returns
  `@teachlink/form-cache/${userId}/v1`.
- All formCache functions now accept a storageKey parameter so data is
  isolated per user.
- useFormCache reads userId from useAppStore and derives storageKey via
  useMemo; cache reloads automatically when userId changes (user switch).

Tests
- src/__tests__/services/mobilePayments.test.ts: valid/invalid receipt
  filtering, finishTransaction only for valid, tier update.
- src/__tests__/services/formCache.test.ts: user-scoped key isolation.
- Updated tests/services/formCache.test.ts and
  tests/hooks/useFormCache.test.ts to match new signatures.

Closes rinafcode#615
Closes rinafcode#616
@drips-wave

drips-wave Bot commented Jun 27, 2026

Copy link
Copy Markdown

@authenticeasy-sys Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER RUKAYAT-CODER merged commit 5cc1e15 into rinafcode:main Jun 27, 2026
2 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants