krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
main: DomainDig/OwnerAccess.swift · raw
1import CloudKit
2
3/// Owner-only entitlement support. The app owner is identified by their CloudKit
4/// user-record ID — a stable, opaque per-Apple-ID value for this app's container.
5/// `PurchaseService` grants the owner Pro+ when the signed-in iCloud user matches,
6/// so the owner does not need a purchase.
7///
8/// Publishing the record ID here is safe: it is not an Apple ID or any personal
9/// identifier, it is scoped to the `iCloud.net.cleberg.DomainDig` container, and
10/// CloudKit identity is verified server-side — another user cannot present it as
11/// their own. An empty value makes the allowlist inert.
12enum OwnerAccess {
13 static let ownerUserRecordID = "_1c35d6a25540b3ef00023cc0425ec373"
14
15 static var isConfigured: Bool { !ownerUserRecordID.isEmpty }
16
17 /// Whether this build actually carries its entitlements.
18 ///
19 /// Touching CloudKit without the iCloud container entitlement does not
20 /// return an error — it raises an Objective-C exception from inside a
21 /// `dispatch_once`, which Swift cannot catch, so the process aborts before
22 /// the first screen draws. That is what any unsigned build does, including
23 /// CI: `xcodebuild ... CODE_SIGNING_ALLOWED=NO` embeds no entitlements.
24 ///
25 /// The App Group is declared in the same entitlements file and is stripped
26 /// by the same mechanism, but asking for its container returns nil rather
27 /// than raising. So it answers the question CloudKit will not: does this
28 /// process have its entitlements at all?
29 private static var hasEntitlements: Bool {
30 FileManager.default.containerURL(
31 forSecurityApplicationGroupIdentifier: DomainDigWidgetStore.appGroupID
32 ) != nil
33 }
34
35 /// The current iCloud user's record name for this app's container, or nil if
36 /// it is unavailable (not signed into iCloud, restricted, offline before the
37 /// first fetch, or running from a build without entitlements).
38 static func currentUserRecordName() async -> String? {
39 guard hasEntitlements else { return nil }
40 do {
41 return try await CKContainer.default().userRecordID().recordName
42 } catch {
43 return nil
44 }
45 }
46
47 /// True only when the allowlist is configured and the current iCloud user is
48 /// the owner.
49 static func isOwner() async -> Bool {
50 guard isConfigured else { return false }
51 return await currentUserRecordName() == ownerUserRecordID
52 }
53}