feat: Y2K theme system, auth security hardening, city passport, and oracle improvements - #6
Merged
Merged
Conversation
In React Native/Hermes, 'crypto' is not accessible as a bare identifier in module scope even on SDK 54. globalThis.crypto is the correct accessor. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
crypto.subtle is not available in all Hermes builds even on Expo SDK 54. Replaced with a self-contained SHA-256 + HMAC-SHA256 + PBKDF2 implementation that works in any JS environment with no native dependencies. Changes: - sha256(), hmacSha256(), hashPassword() — pure JS, synchronous, spec-correct - 10k iterations (down from 100k) to keep it fast in pure JS (~200-400ms on Hermes) - makeSalt() tries globalThis.crypto.getRandomValues first, falls back to xorshift + Date entropy if not available - hashPassword() wrapped in Promise so callers stay async-compatible Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ests, TODOS updates
…ing-safe password comparison - Migrate all credential storage from AsyncStorage to expo-secure-store (encrypted at rest) - Add rawNonce generation in AuthScreen.tsx + SHA-256 hash passed to Apple sign-in - Verify nonce binding server-side in cloudflare-worker/lib/apple.js (prevents SIWA replay attacks) - Add iat age check (max 10 min) to Apple token verification - Add timingSafeEqual() XOR loop to prevent timing side-channels on password comparison - makeSalt() now throws instead of silently falling back to Math.random if CSPRNG unavailable - Pass nonce through AuthContext.tsx → authApi.ts → cloudflare worker - Refactor worker to modular routes/ + lib/ structure with route-level input validation - Cap city/country to 100 chars, negative_prompt to 1000 chars, data payloads to 256KB/64KB - Clarify EXPO_PUBLIC_FAL_KEY is development-only in .env.example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntCities, image gen, outfit selection - Add expo-secure-store mock with _clear() for test isolation - Update auth.test.ts to use SecureStore mock (clears state between tests) - Add wordUsage.test.ts: 8 tests for fashionUsageFor() — accents, hyphens, multi-word French - Add recentCities.test.ts: 7 regression tests for case-insensitive city dedup fix - Add fashionCapitals.test.ts, imageGeneration.test.ts, locationTime.test.ts, outfitSelection.test.ts, shoppingLinks.test.ts (tests for services added this branch) - Update oracle.test.ts, oracleProxy.test.ts, theme.test.ts, weatherAlerts.test.ts, weatherBadges.test.ts to cover new code paths - Add SecureStore mock mapping to jest.config.js moduleNameMapper Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… notifications - Add city passport system (useCityPassport, PassportPageCard, CityArrivalModal, CityReturnBanner) - Add oracle accuracy tracking (useOracleAccuracy) for rating outfit suggestions - Add outfit rating prompt component (OutfitRatingPrompt, UnlockToast) - Add shopping links service (shoppingLinks.ts) for affiliate item search - Add cloud data sync service (cloudData.ts) for cross-device history/saved/archive - Add city descriptor service (cityDescriptor.ts) for location-aware editorial copy - Add notifications hook (useNotifications) for push notification management - Add outfit selection utility (outfitSelection.ts) and location time helper (locationTime.ts) - Add SunnyWeatherAnimation component for weather animations - Add local outfit data (src/data/) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, and Oracle improvements - Update OracleScreen, TodayScreen, YouScreen, SettingsScreen with new feature integrations - Update MapScreen with city passport and city return banner - Update Y2KOracleScreen, Y2KTodayScreen and Mondrian screens with theme refinements - Update ProfileEditScreen with cloud data sync - Update HourlyGraph with improved rendering - Update WeatherGlanceCard, WeatherAlertBanner with new weather features - Update OutfitCard, ShareCard, AvoidSection with shopping links and rating support - Update OracleImage with improved generation flow - Update useOracle, useOracleImage, useArchive, useConsultStreak, useSavedOutfits, useOutfitHistory, useStyleProfile, useWeatherBadges hooks - Update oracle.ts, weather.ts, imageGeneration.ts services - Update theme/index.ts with Y2K refinements Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cies - Update iOS project config (AppDelegate.swift, Bridging-Header, entitlements, Info.plist) - Update Podfile and Podfile.lock with latest native dependencies - Remove legacy AppDelegate.h/mm and noop-file.swift (Swift-only project) - Add SplashScreenLegacy and SplashScreenBackground.colorset assets - Update app.json with new build config - Bump android/gradle.properties - Update storm/sunny weather glance card animations - Update package.json and package-lock.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update TODOS.md with new feature backlog and completed items - Update ARCHITECTURE.md with cloudflare worker refactoring notes and new services - Update DESIGN.md with Y2K theme refinements - Update README.md with setup and feature documentation - Update BEST_PRACTICES.md with auth security guidelines - Update AFFILIATE_STRATEGY.md and IMAGE_GENERATION.md - Add MARKETING.md for launch strategy - Add .reap/ genome and environment configuration - Add .github/ CI/CD workflows - Update CLAUDE.md with skill routing and learned rules - Update Roadmap.md with completed Y2K milestone - Update orchestrator.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Client: - Add expo-auth-session + expo-web-browser + expo-crypto (SDK 54 compatible) - AuthScreen: Google and Facebook OAuth buttons using useAuthRequest hooks (buttons are conditionally rendered — only shown when client IDs are configured) - auth.ts: add signInWithGoogle / signInWithFacebook — same pattern as SIWA, stores googleUserId / facebookUserId in SecureStore - authApi.ts: add cloudSignInWithGoogle (idToken) / cloudSignInWithFacebook (accessToken) - AuthContext: expose signInWithGoogle / signInWithFacebook, mirrors SIWA cloud+local flow Server (Cloudflare Worker): - lib/google.js: verify Google ID token via tokeninfo endpoint, validate aud + exp - lib/facebook.js: verify Facebook access token via debug_token endpoint, fetch profile - routes/auth.js: POST /auth/google and POST /auth/facebook — upsert user, issue session - schema.sql: add google_sub + facebook_sub columns (apple_sub now nullable) - migrations/001_social_auth.sql: ALTER TABLE migration for existing databases Config: - .env.example: EXPO_PUBLIC_GOOGLE_CLIENT_ID, EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID, EXPO_PUBLIC_FACEBOOK_APP_ID - wrangler.toml: document GOOGLE_CLIENT_ID, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET secrets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
expo-secure-store(encrypted at rest), add SIWA nonce binding to prevent replay attacks, add timing-safe password comparison via XOR loop, and hardenmakeSalt()to throw on unavailable CSPRNGroutes/+lib/with input validation (size caps on city/payload inputs, 256KB data limit)Y2KDecreeCard,Y2KWeatherCard,Y2KOutfitCard,Y2KAvoidSection, font subthemes (Decree/Club), andY2KOracleScreenthin-router integrationuseOracleAccuracySecurity changes
iatage check (max 10 min)timingSafeEqual()for password hashesmakeSalt()throws on weak PRNGTest plan
npm test— 187 tests should passnpx tsc --noEmit— no type errors🤖 Generated with Claude Code