keys-for-all/docs/VUKeyServerIntegration.md
2025-07-22 18:27:21 -07:00

18 KiB

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

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

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

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

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

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

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

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

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

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

// 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

{
    "keyserver": {
        "baseUrl": "https://api.voiceuwu.com",
        "timeout": 15000,
        "retryAttempts": 2
    },
    "apple": {
        "bundleId": "com.uwuapps.VoiceUwu",
        "environment": "production"
    }
}

Client Configuration

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
  • VU Key Web Portal: User-facing web application for key management, sharing, and purchasing