GameEntity+ContentKey.swift (1269B)
1 import CoreData 2 import Foundation 3 4 extension GameEntity { 5 /// Rewrites the App Group content-key directory from Core Data ground truth: 6 /// one `gameID → contentKey` entry per shared game whose notification 7 /// credentials carry a key. The Notification Service Extension reads it to 8 /// decrypt the structured push payload (`PushPayloadCipher`) on a suspended 9 /// device, where it can't reach Core Data. Called after a local mint 10 /// (`GameStore.setNotification`), after sync adopts an inbound credential, 11 /// and once at launch as a heal. Must run inside the context's queue 12 /// (`performAndWait`) when `ctx` is a background context. 13 static func rebuildContentKeyDirectory(in ctx: NSManagedObjectContext) { 14 let req = NSFetchRequest<GameEntity>(entityName: "GameEntity") 15 req.predicate = NSPredicate(format: "notification != nil") 16 var directory: [String: String] = [:] 17 for game in (try? ctx.fetch(req)) ?? [] { 18 guard let id = game.id, 19 let key = GamePushCredentials.decode(game.notification)?.contentKey, 20 !key.isEmpty 21 else { continue } 22 directory[id.uuidString] = key 23 } 24 ContentKeyDirectory.save(directory) 25 } 26 }