# VUKeyServerIntegration Component ## Overview The VUKeyServerIntegration component handles license key retrieval and syncing for VoiceUwu in an **offline-first** architecture. The app functions completely offline, with the keyserver only used for purchasing and retrieving keys associated with the user's account. ## Architecture (Offline-First) ``` ┌─────────────────────────────────┐ ┌─────────────────┐ ┌─────────────────────────────────┐ │ iOS App │ │ Your Server │ │ Android App │ │ (Offline-First) │ │ (KeyServer) │ │ (Offline-First) │ │ │ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ ┌─────────────────────────────┐ │ │ │ Local Key Storage │ │ │ │ │ │ Local Key Storage │ │ │ │ - Encrypted in Keychain │ │ │ │ │ │ - Encrypted locally │ │ │ │ - Full offline validation │ │ │ │ │ │ - Full offline validation │ │ │ │ - No network required │ │ │ │ │ │ - No network required │ │ │ └─────────────────────────────┘ │ │ │ │ └─────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ ┌─────────────────────────────┐ │ │ │ Keys for All Feature │ │ │ │ │ │ Keys for All Feature │ │ │ │ - Auto-check on open │ │ │ │ │ │ - Auto-check on open │ │ │ │ - Manual sync button │ │ │ │ │ │ - Manual sync button │ │ │ │ - Shows available keys │ │ │ │ │ │ - Shows available keys │ │ │ └─────────────────────────────┘ │ │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────┘ └─────────────────┘ └─────────────────────────────────┘ │ │ │ │ Sync: Get user's keys │ │ │──────────────────────────────→│ │ │ │ │ │ Response: [key1, key2, ...] │ │ │←──────────────────────────────│ │ │ │ │ │ │ Sync: Get user's keys │ │ │←──────────────────────────────│ │ │ │ │ │ Response: [key1, key2, ...] │ │ │──────────────────────────────→│ ``` ## Components ### 1. VUKeyServerClient **Purpose**: Client for keyserver communication (purchase, wallet management, feature unlocking) **Platform**: Cross-platform interface supporting multiple apps ```swift protocol VUKeyServerClient { // Multi-platform key pack purchasing func purchaseKeyPack(pack: KeyPack, via platform: Platform) async throws -> KeyPurchaseResult // Wallet management func getWalletBalance(userId: String) async throws -> Int func spendKeys(amount: Int, feature: String, app: String, userId: String) async throws -> SpendResult func syncWallet(userId: String) async throws -> WalletState // App-specific features func getAppFeatures(appId: String) async throws -> [AppFeature] func unlockFeature(featureId: String, appId: String, userId: String) async throws -> UnlockResult func getUserFeatures(userId: String, appId: String) async throws -> [String] // Community features func donateKeys(amount: Int, userId: String) async throws -> DonationResult func shareKeys(amount: Int, recipientEmail: String, userId: String) async throws -> ShareResult } enum Platform { case apple, google, stripe, paypal, steam } struct KeyPurchaseResult { let keysAdded: Int let bonusKeys: Int let communityDonated: Int let transactionId: String } struct SpendResult { let remainingBalance: Int let featureUnlocked: Bool let transactionId: String } ``` ### 2. Platform-Specific Purchase Managers #### VUAppleStoreKitManager **Purpose**: Handle Apple App Store purchases (iOS/macOS) **Platform**: iOS/macOS ```swift class VUAppleStoreKitManager { func purchaseProduct(_ productId: String) async throws -> StoreKit.Transaction func restorePurchases() async throws -> [StoreKit.Transaction] func sendTransactionToKeyServer(_ transaction: StoreKit.Transaction) async throws -> [VULicenseKey] } ``` #### VUGooglePlayManager **Purpose**: Handle Google Play purchases (Android) **Platform**: Android ```swift class VUGooglePlayManager { func purchaseProduct(_ productId: String) async throws -> GooglePlayPurchase func sendPurchaseToKeyServer(_ purchase: GooglePlayPurchase) async throws -> [VULicenseKey] } ``` #### VUStripeManager **Purpose**: Handle Stripe payments (Web/Direct) **Platform**: Web/Cross-platform ```swift class VUStripeManager { func createPaymentIntent(amount: Int, email: String) async throws -> String func confirmPaymentAndGetKeys(_ paymentIntentId: String) async throws -> [VULicenseKey] } ``` #### VUPayPalManager **Purpose**: Handle PayPal payments (Web/Direct) **Platform**: Web/Cross-platform ```swift class VUPayPalManager { func createPayment(amount: Double, email: String) async throws -> String func executePaymentAndGetKeys(_ paymentId: String) async throws -> [VULicenseKey] } ``` #### VUSteamManager **Purpose**: Handle Steam purchases (PC Gaming) **Platform**: PC/Steam ```swift class VUSteamManager { func initiateSteamPurchase(_ productId: String) async throws -> String func validateSteamPurchaseAndGetKeys(_ transactionId: String) async throws -> [VULicenseKey] } ``` ### 3. VUKeysForAllSync **Purpose**: Handles the "Keys for All" feature sync functionality **Platform**: iOS/Android ```swift class VUKeysForAllSync { private let keyServerClient: VUKeyServerClient private let keyStorage: VUKeyStorage // Auto-sync when feature is opened func autoSyncOnOpen() async throws -> [VULicenseKey] // Manual sync via button func manualSync() async throws -> [VULicenseKey] // Check if user has account/email for syncing func canSync() -> Bool // Store retrieved keys locally func storeRetrievedKeys(_ keys: [VULicenseKey]) async throws } ``` ## Data Models ### VULicenseKey ```swift struct VULicenseKey: Codable { let keyValue: String // The actual license key (e.g., "VUUW-ABCD-1234-WXYZ-L2") let planType: VUPlanType // Level 1, Level 2, etc. let purchaseDate: Date // When it was purchased let serverMetadata: [String: Any]? // Optional server data } ``` ### VUUserKeySync ```swift struct VUUserKeySync: Codable { let userEmail: String let availableKeys: [VULicenseKey] let syncTimestamp: Date } ``` ## Integration Flows ### Purchase Flow (Apple - iOS/macOS) 1. User initiates purchase in iOS/macOS app 2. StoreKit 2 handles payment with Apple 3. App receives JWS-signed transaction 4. App sends transaction to keyserver via `purchaseWithApple()` 5. Keyserver validates JWS signature and generates keys 6. Keyserver returns generated keys to app 7. App stores keys locally using KeyStorage ### Purchase Flow (Google Play - Android) 1. User initiates purchase in Android app 2. Google Play Billing handles payment 3. App receives purchase token 4. App sends purchase token to keyserver via `purchaseWithGoogle()` 5. Keyserver validates with Google Play API and generates keys 6. Keyserver returns generated keys to app 7. App stores keys locally ### Purchase Flow (Stripe - Web/Direct) 1. User completes payment on website/web app 2. Stripe processes payment and returns payment intent ID 3. Client calls `purchaseWithStripe()` with payment intent and email 4. Keyserver validates with Stripe API and generates keys 5. Keyserver returns generated keys 6. Keys stored locally in app ### Purchase Flow (PayPal - Web/Direct) 1. User completes payment via PayPal 2. PayPal processes payment and returns payment ID 3. Client calls `purchaseWithPayPal()` with payment ID and email 4. Keyserver validates with PayPal API and generates keys 5. Keyserver returns generated keys 6. Keys stored locally in app ### Purchase Flow (Steam - PC Gaming) 1. User purchases through Steam store 2. Steam processes payment and provides transaction ID 3. Steam client calls `purchaseWithSteam()` with Steam ID and transaction 4. Keyserver validates with Steam Web API and generates keys 5. Keyserver returns generated keys 6. Keys stored locally in Steam client/game ### Keys for All Feature Flow 1. User opens "Keys for All" feature 2. App calls `autoSyncOnOpen()` which: - Checks if user has email/account configured - Calls `syncUserKeys()` if available - Compares server keys with local keys - Stores any new keys locally 3. User can tap "Sync" button to trigger `manualSync()` 4. All keys stored locally work offline immediately ## Server-Side Integration ### Endpoints ``` # Key pack purchase endpoints POST /api/v1/keys/purchase/apple # Process Apple key pack purchase POST /api/v1/keys/purchase/google # Process Google Play key pack purchase POST /api/v1/keys/purchase/stripe # Process Stripe key pack payment POST /api/v1/keys/purchase/paypal # Process PayPal key pack payment POST /api/v1/keys/purchase/steam # Process Steam key pack purchase # Wallet management endpoints GET /api/v1/wallet/:userId # Get user's key wallet balance POST /api/v1/wallet/spend # Spend keys on app feature POST /api/v1/wallet/sync # Sync wallet across devices GET /api/v1/wallet/history/:userId # Get spending transaction history # App feature endpoints GET /api/v1/apps/:appId/features # Get app's feature definitions POST /api/v1/apps/:appId/unlock # Unlock feature in specific app GET /api/v1/apps/:appId/unlocked/:userId # Get user's unlocked features # Community endpoints POST /api/v1/community/donate # Donate keys to community pool POST /api/v1/community/share # Share keys with another user GET /api/v1/community/pool # Get community pool status ``` ### Platform Validation Examples ```javascript // Apple JWS Validation const jwt = require('jsonwebtoken'); const appleRootCert = loadAppleRootCertificate(); function validateAppleTransaction(jws) { try { const decoded = jwt.verify(jws, appleRootCert, { algorithms: ['ES256'], issuer: 'https://appleid.apple.com' }); return decoded; } catch (error) { throw new Error('Invalid Apple transaction'); } } // Google Play Validation async function validateGooglePlayPurchase(purchaseToken, productId) { const response = await googlePlayAPI.purchases.products.get({ packageName: 'com.uwuapps.voiceuwu', productId: productId, token: purchaseToken }); return response.data; } // Stripe Validation async function validateStripePayment(paymentIntentId) { const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId); if (paymentIntent.status !== 'succeeded') { throw new Error('Payment not completed'); } return paymentIntent; } // PayPal Validation async function validatePayPalPayment(paymentId) { const payment = await paypal.payment.get(paymentId); if (payment.state !== 'approved') { throw new Error('Payment not approved'); } return payment; } // Steam Validation async function validateSteamPurchase(steamId, transactionId) { const response = await steamWebAPI.GetUserInfo({ steamid: steamId, transactionid: transactionId }); return response; } // Purchase endpoints app.post('/api/v1/purchase/apple', async (req, res) => { const { transaction, userEmail } = req.body; const validated = validateAppleTransaction(transaction); const keys = generateKeysForPurchase(validated.productId, userEmail); await storeUserKeys(userEmail, keys); res.json({ keys }); }); app.post('/api/v1/purchase/google', async (req, res) => { const { purchaseToken, productId, userEmail } = req.body; const validated = await validateGooglePlayPurchase(purchaseToken, productId); const keys = generateKeysForPurchase(productId, userEmail); await storeUserKeys(userEmail, keys); res.json({ keys }); }); app.post('/api/v1/purchase/stripe', async (req, res) => { const { paymentIntentId, userEmail } = req.body; const validated = await validateStripePayment(paymentIntentId); const keys = generateKeysForPurchase(validated.metadata.productId, userEmail); await storeUserKeys(userEmail, keys); res.json({ keys }); }); app.post('/api/v1/purchase/paypal', async (req, res) => { const { paymentId, userEmail } = req.body; const validated = await validatePayPalPayment(paymentId); const keys = generateKeysForPurchase(validated.transactions[0].item_list.items[0].sku, userEmail); await storeUserKeys(userEmail, keys); res.json({ keys }); }); app.post('/api/v1/purchase/steam', async (req, res) => { const { steamId, transactionId } = req.body; const validated = await validateSteamPurchase(steamId, transactionId); const keys = generateKeysForPurchase(validated.productId, steamId); await storeUserKeys(steamId, keys, 'steam'); res.json({ keys }); }); // Key sync endpoints app.get('/api/v1/keys/email/:email', async (req, res) => { const { email } = req.params; const keys = await getUserKeys(email); res.json({ keys }); }); app.get('/api/v1/keys/steam/:steamId', async (req, res) => { const { steamId } = req.params; const keys = await getUserKeys(steamId, 'steam'); res.json({ keys }); }); ``` ## Security Features ### Transaction Integrity - Apple JWS signature validation - HTTPS for all API calls - Rate limiting on sync endpoints - Input validation and sanitization ### Key Protection - Hardware-backed keystore (iOS Keychain) - Encrypted local storage - Local-only key validation - No device binding required (offline-first) ## Error Handling ### Network Errors (Sync Only) - Graceful failure - app continues working offline - Retry logic with exponential backoff - User feedback on sync failures - Cached keys always work ### Sync Errors - Invalid email/token handling - Server unavailable scenarios - Network timeout handling - Malformed response handling ## Configuration ### Server Configuration ```json { "keyserver": { "baseUrl": "https://api.voiceuwu.com", "timeout": 15000, "retryAttempts": 2 }, "apple": { "bundleId": "com.uwuapps.VoiceUwu", "environment": "production" } } ``` ### Client Configuration ```swift struct VUKeyServerConfig { let baseUrl: URL let timeout: TimeInterval = 15.0 // Shorter timeout for sync let retryAttempts: Int = 2 // Fewer retries for sync let autoSyncOnOpen: Bool = true // Auto-sync when Keys for All opens let syncCooldown: TimeInterval = 300 // 5 minutes between auto-syncs } ``` ## Testing Strategy ### Unit Tests - Mock keyserver responses for sync operations - Apple transaction validation - Offline-first key validation logic - Error handling scenarios (network failures) ### Integration Tests - End-to-end purchase flow - Keys for All sync functionality - Network failure scenarios (app continues working) - Cross-platform key sharing ## Implementation Notes 1. **Offline-First**: App must work completely offline - network only for sync/purchase 2. **Multi-Platform Support**: Single keyserver supports Apple, Google, Stripe, PayPal, and Steam 3. **Platform Requirements**: - Apple: StoreKit 2 for iOS/macOS - Google: Play Billing API for Android - Stripe: Payment Intents API for web/direct - PayPal: REST API for web/direct - Steam: Web API for PC gaming 4. **Server Validation**: Each platform has its own validation method 5. **Minimal Network**: 8 endpoints total (5 purchase + 3 sync) 6. **User Experience**: Auto-sync on feature open + manual sync button 7. **Cross-Platform Keys**: Same keys work across all platforms once synced 8. **No Session Management**: Stateless key retrieval by email/token/steamId 9. **Security**: Local key validation, HTTPS for sync, encrypted storage 10. **Web Portal Integration**: Keys purchased through web portal immediately sync to all platforms ## Related Documentation - **[VU Key Web Portal](./VUKeyWebPortal.md)**: User-facing web application for key management, sharing, and purchasing