summaryrefslogtreecommitdiff
path: root/DomainDig/OwnerAccess.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-07-25 12:14:58 -0500
committerChristian Cleberg <[email protected]>2026-07-25 12:19:37 -0500
commit963ce3fb34bd6c6bd72f1aa956ce602267b90e9c (patch)
treeba2c18e4c2bebba8d07a6715e07bd1fccbea4581 /DomainDig/OwnerAccess.swift
parent7156c088a438526182c517fafa35d31990d44f18 (diff)
downloaddomain-dig-5.0.1.tar.gz
domain-dig-5.0.1.tar.bz2
domain-dig-5.0.1.zip
feat: owner Pro+ allowlist via CloudKit, cut v5.0.1v5.0.1
Grants the app owner Pro+ without a purchase, keyed to their CloudKit user-record ID so it works on the release App Store build. - OwnerAccess holds the owner's CloudKit user-record ID (opaque, per-Apple-ID, scoped to the app's container; safe to publish — CloudKit verifies identity server-side, so it can't be presented by anyone else). - PurchaseService resolves the allowlist against CloudKit once per launch and, on a match, records a persisted owner grant so it applies instantly and offline thereafter. The grant only ever elevates the tier to .proPlus and defers to the existing #if DEBUG overrides, so real purchases and free/pro testing are unaffected. cachedTier / cachedEntitlement were refactored to fall back to the owner grant only when no debug override or stored purchase applies. - Supersedes the DEBUG record-ID reveal (PR #60): its only purpose was to read the owner's ID, which is now hardcoded, so the reveal is not shipped. Release cut: MARKETING_VERSION 5.0.0 -> 5.0.1, CURRENT_PROJECT_VERSION 45 -> 46, AppVersion.current -> 5.0.1, roadmap updated. App builds clean; unit suite 63/63.
Diffstat (limited to 'DomainDig/OwnerAccess.swift')
-rw-r--r--DomainDig/OwnerAccess.swift34
1 files changed, 34 insertions, 0 deletions
diff --git a/DomainDig/OwnerAccess.swift b/DomainDig/OwnerAccess.swift
new file mode 100644
index 0000000..eca2bab
--- /dev/null
+++ b/DomainDig/OwnerAccess.swift
@@ -0,0 +1,34 @@
+import CloudKit
+
+/// Owner-only entitlement support. The app owner is identified by their CloudKit
+/// user-record ID — a stable, opaque per-Apple-ID value for this app's container.
+/// `PurchaseService` grants the owner Pro+ when the signed-in iCloud user matches,
+/// so the owner does not need a purchase.
+///
+/// Publishing the record ID here is safe: it is not an Apple ID or any personal
+/// identifier, it is scoped to the `iCloud.net.cleberg.DomainDig` container, and
+/// CloudKit identity is verified server-side — another user cannot present it as
+/// their own. An empty value makes the allowlist inert.
+enum OwnerAccess {
+ static let ownerUserRecordID = "_1c35d6a25540b3ef00023cc0425ec373"
+
+ static var isConfigured: Bool { !ownerUserRecordID.isEmpty }
+
+ /// The current iCloud user's record name for this app's container, or nil if
+ /// it is unavailable (not signed into iCloud, restricted, or offline before
+ /// the first fetch).
+ static func currentUserRecordName() async -> String? {
+ do {
+ return try await CKContainer.default().userRecordID().recordName
+ } catch {
+ return nil
+ }
+ }
+
+ /// True only when the allowlist is configured and the current iCloud user is
+ /// the owner.
+ static func isOwner() async -> Bool {
+ guard isConfigured else { return false }
+ return await currentUserRecordName() == ownerUserRecordID
+ }
+}