From 0beb5a5a959569bfc733a9904417bd7aaefda83d Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Fri, 17 Jan 2025 17:46:54 +0100 Subject: [PATCH 1/2] track mac installations --- Nos/Extensions/Bundle+Current.swift | 52 +++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/Nos/Extensions/Bundle+Current.swift b/Nos/Extensions/Bundle+Current.swift index f8b2fdf22..a8ecb6cb2 100644 --- a/Nos/Extensions/Bundle+Current.swift +++ b/Nos/Extensions/Bundle+Current.swift @@ -1,4 +1,5 @@ import Foundation +import Security private class CurrentBundle {} @@ -33,16 +34,63 @@ extension Bundle { /// Checks the app's receipt URL to determine if it contains the TestFlight-specific /// "sandboxReceipt" identifier. /// - Returns: `true` if the app was installed through TestFlight, `false` otherwise. - private var isTestFlight: Bool { + private var isIosTestFlight: Bool { Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" } + /// Returns whether the bundle was signed for TestFlight beta distribution by checking + /// the existence of a specific extension (marker OID) on the code signing certificate. + /// + /// This routine is inspired by the source code from ProcInfo, the underlying library + /// of the WhatsYourSign code signature checking tool developed by Objective-See. Initially, + /// it checked the common name but was changed to an extension check to make it more + /// future-proof. + /// + /// For more information, see the following references: + /// - https://github.com/objective-see/ProcInfo/blob/master/procInfo/Signing.m#L184-L247 + /// - https://gist.github.com/lukaskubanek/cbfcab29c0c93e0e9e0a16ab09586996#gistcomment-3993808 + private var isMacTestFlight: Bool { + #if os(macOS) + var status = noErr + + var code: SecStaticCode? + status = SecStaticCodeCreateWithPath(bundleURL as CFURL, [], &code) + + guard status == noErr, let code = code else { return false } + + var requirement: SecRequirement? + status = SecRequirementCreateWithString( + "anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.25.1]" as CFString, + [], // default + &requirement + ) + + guard status == noErr, let requirement = requirement else { return false } + + status = SecStaticCodeCheckValidity( + code, + [], // default + requirement + ) + + return status == errSecSuccess + #else + return false + #endif + } + /// Returns the app's installation source: debug, TestFlight, or App Store. var installationSource: InstallationSource { #if DEBUG return .debug #else - return isTestFlight ? .testFlight : .appStore + #if os(iOS) + return isIosTestFlight ? .testFlight : .appStore + #elseif os(macOS) + return isMacTestFlight ? .testFlight : .appStore + #else + return .debug + #endif #endif } } From 330a34c324bb75d3d523497608a6505128558b02 Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Tue, 21 Jan 2025 18:51:20 +0100 Subject: [PATCH 2/2] refactor code --- Nos/Extensions/Bundle+Current.swift | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Nos/Extensions/Bundle+Current.swift b/Nos/Extensions/Bundle+Current.swift index a8ecb6cb2..d574d55ae 100644 --- a/Nos/Extensions/Bundle+Current.swift +++ b/Nos/Extensions/Bundle+Current.swift @@ -29,18 +29,14 @@ extension Bundle { } /// > Warning: This method relies on undocumented implementation details to determine the installation source - /// and may break in future iOS releases. - /// https://gist.github.com/lukaskubanek/cbfcab29c0c93e0e9e0a16ab09586996 - /// Checks the app's receipt URL to determine if it contains the TestFlight-specific - /// "sandboxReceipt" identifier. - /// - Returns: `true` if the app was installed through TestFlight, `false` otherwise. - private var isIosTestFlight: Bool { - Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" - } + /// and may break in future iOS / macOS releases. /// Returns whether the bundle was signed for TestFlight beta distribution by checking - /// the existence of a specific extension (marker OID) on the code signing certificate. + /// the existence of a specific extension (marker OID) on the code signing certificate on macOS. /// + /// Checks the app's receipt URL to determine if it contains the TestFlight-specific + /// "sandboxReceipt" identifier on iOS. + /// - Returns: `true` if the app was installed through TestFlight, `false` otherwise. /// This routine is inspired by the source code from ProcInfo, the underlying library /// of the WhatsYourSign code signature checking tool developed by Objective-See. Initially, /// it checked the common name but was changed to an extension check to make it more @@ -49,7 +45,7 @@ extension Bundle { /// For more information, see the following references: /// - https://github.com/objective-see/ProcInfo/blob/master/procInfo/Signing.m#L184-L247 /// - https://gist.github.com/lukaskubanek/cbfcab29c0c93e0e9e0a16ab09586996#gistcomment-3993808 - private var isMacTestFlight: Bool { + private var isTestFlight: Bool { #if os(macOS) var status = noErr @@ -74,6 +70,8 @@ extension Bundle { ) return status == errSecSuccess + #elseif os(iOS) + Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" #else return false #endif @@ -84,13 +82,7 @@ extension Bundle { #if DEBUG return .debug #else - #if os(iOS) - return isIosTestFlight ? .testFlight : .appStore - #elseif os(macOS) - return isMacTestFlight ? .testFlight : .appStore - #else - return .debug - #endif + return isTestFlight ? .testFlight : .appStore #endif } }