From 82df8f8188b26d5955c8c71f3f40f3bd15b7a584 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sat, 6 Aug 2016 17:25:11 +0300 Subject: [PATCH 01/23] Added mac os version. --- RMStore.podspec | 4 +- RMStore.xcodeproj/project.pbxproj | 212 ++++++ RMStore/Optional/RMAppReceipt.m | 55 +- RMStore/Optional/RMStoreTransaction.h | 3 - RMStore/Optional/RMStoreTransaction.m | 16 +- RMStoreDemo_OSX/AppDelegate.h | 15 + RMStoreDemo_OSX/AppDelegate.m | 34 + .../AppIcon.appiconset/Contents.json | 58 ++ RMStoreDemo_OSX/Base.lproj/Main.storyboard | 681 ++++++++++++++++++ RMStoreDemo_OSX/Info.plist | 34 + RMStoreDemo_OSX/ViewController.h | 15 + RMStoreDemo_OSX/ViewController.m | 25 + RMStoreDemo_OSX/main.m | 13 + RMStoreTests/RMStoreTransactionTests.m | 16 +- .../RMStoreUserDefaultsPersistenceTests.m | 8 +- 15 files changed, 1153 insertions(+), 36 deletions(-) create mode 100644 RMStoreDemo_OSX/AppDelegate.h create mode 100644 RMStoreDemo_OSX/AppDelegate.m create mode 100644 RMStoreDemo_OSX/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 RMStoreDemo_OSX/Base.lproj/Main.storyboard create mode 100644 RMStoreDemo_OSX/Info.plist create mode 100644 RMStoreDemo_OSX/ViewController.h create mode 100644 RMStoreDemo_OSX/ViewController.m create mode 100644 RMStoreDemo_OSX/main.m diff --git a/RMStore.podspec b/RMStore.podspec index 3e89f892..6f8905df 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -7,10 +7,12 @@ Pod::Spec.new do |s| s.author = 'Hermes Pique' s.social_media_url = 'https://twitter.com/hpique' s.source = { :git => 'https://github.com/robotmedia/RMStore.git', :tag => "v#{s.version}" } - s.platform = :ios, '7.0' s.frameworks = 'StoreKit' s.requires_arc = true s.default_subspec = 'Core' + + s.ios.deployment_target = '7.0' + s.osx.deployment_target = '10.7' s.subspec 'Core' do |core| core.source_files = 'RMStore/*.{h,m}' diff --git a/RMStore.xcodeproj/project.pbxproj b/RMStore.xcodeproj/project.pbxproj index f7da0a58..ebc91994 100644 --- a/RMStore.xcodeproj/project.pbxproj +++ b/RMStore.xcodeproj/project.pbxproj @@ -7,6 +7,22 @@ objects = { /* Begin PBXBuildFile section */ + 52FE63A41D3531B00050814B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A31D3531B00050814B /* AppDelegate.m */; }; + 52FE63A71D3531B00050814B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A61D3531B00050814B /* main.m */; }; + 52FE63AA1D3531B00050814B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A91D3531B00050814B /* ViewController.m */; }; + 52FE63AC1D3531B00050814B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52FE63AB1D3531B00050814B /* Assets.xcassets */; }; + 52FE63AF1D3531B00050814B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52FE63AD1D3531B00050814B /* Main.storyboard */; }; + 52FE63B41D35333F0050814B /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8793E797180C2ABE005D7A66 /* libcrypto.a */; }; + 52FE63B51D35333F0050814B /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8793E798180C2ABE005D7A66 /* libssl.a */; }; + 52FE63B91D3534390050814B /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52FE63B81D3534390050814B /* StoreKit.framework */; }; + 52FE63BB1D3534450050814B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52FE63BA1D3534450050814B /* Security.framework */; }; + 52FE63BE1D3535A00050814B /* RMAppReceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E801180D512E005D7A66 /* RMAppReceipt.m */; }; + 52FE63C01D3535A00050814B /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; + 52FE63C21D3535A00050814B /* RMStoreKeychainPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 876046481812FB7500C9B78C /* RMStoreKeychainPersistence.m */; }; + 52FE63C41D3535A00050814B /* RMStoreTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 876631F8180EEBF40049B368 /* RMStoreTransaction.m */; }; + 52FE63C61D3535A00050814B /* RMStoreTransactionReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */; }; + 52FE63C81D3535A00050814B /* RMStoreUserDefaultsPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 87A2A3A8180E82BB00376773 /* RMStoreUserDefaultsPersistence.m */; }; + 52FE63CA1D3535A00050814B /* RMStore.m in Sources */ = {isa = PBXBuildFile; fileRef = A0AF3D1217A802F300D2E836 /* RMStore.m */; }; 8700D1C117DCA548005C8F5D /* NSNotification+RMStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8700D1C017DCA548005C8F5D /* NSNotification+RMStoreTests.m */; }; 8700D1D717DCB011005C8F5D /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8700D1D617DCB011005C8F5D /* libOCMock.a */; }; 876046491812FB7500C9B78C /* RMStoreKeychainPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 876046481812FB7500C9B78C /* RMStoreKeychainPersistence.m */; }; @@ -84,6 +100,17 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 52FE63A01D3531B00050814B /* RMStoreDemo_OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RMStoreDemo_OSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 52FE63A21D3531B00050814B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 52FE63A31D3531B00050814B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 52FE63A61D3531B00050814B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 52FE63A81D3531B00050814B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + 52FE63A91D3531B00050814B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 52FE63AB1D3531B00050814B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 52FE63AE1D3531B00050814B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 52FE63B01D3531B00050814B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 52FE63B81D3534390050814B /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; }; + 52FE63BA1D3534450050814B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 8700D1C017DCA548005C8F5D /* NSNotification+RMStoreTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNotification+RMStoreTests.m"; sourceTree = ""; }; 8700D1CF17DCB011005C8F5D /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = ""; }; 8700D1D017DCB011005C8F5D /* OCMArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = ""; }; @@ -147,6 +174,17 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 52FE639D1D3531B00050814B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 52FE63BB1D3534450050814B /* Security.framework in Frameworks */, + 52FE63B91D3534390050814B /* StoreKit.framework in Frameworks */, + 52FE63B41D35333F0050814B /* libcrypto.a in Frameworks */, + 52FE63B51D35333F0050814B /* libssl.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; A0AF3D0517A802F300D2E836 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -189,6 +227,29 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 52FE63A11D3531B00050814B /* RMStoreDemo_OSX */ = { + isa = PBXGroup; + children = ( + 52FE63A21D3531B00050814B /* AppDelegate.h */, + 52FE63A31D3531B00050814B /* AppDelegate.m */, + 52FE63A81D3531B00050814B /* ViewController.h */, + 52FE63A91D3531B00050814B /* ViewController.m */, + 52FE63AB1D3531B00050814B /* Assets.xcassets */, + 52FE63AD1D3531B00050814B /* Main.storyboard */, + 52FE63B01D3531B00050814B /* Info.plist */, + 52FE63A51D3531B00050814B /* Supporting Files */, + ); + path = RMStoreDemo_OSX; + sourceTree = ""; + }; + 52FE63A51D3531B00050814B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 52FE63A61D3531B00050814B /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; 8700D1CC17DCB011005C8F5D /* usr */ = { isa = PBXGroup; children = ( @@ -253,6 +314,7 @@ A0AF3D0D17A802F300D2E836 /* RMStore */, A0AF3D2217A802F300D2E836 /* RMStoreTests */, A0AF3D7617A8085900D2E836 /* RMStoreDemo */, + 52FE63A11D3531B00050814B /* RMStoreDemo_OSX */, A0AF3D0A17A802F300D2E836 /* Frameworks */, A0AF3D0917A802F300D2E836 /* Products */, ); @@ -264,6 +326,7 @@ A0AF3D0817A802F300D2E836 /* libRMStore.a */, A0AF3D1917A802F300D2E836 /* RMStoreTests.xctest */, A0AF3D7217A8085900D2E836 /* RMStoreDemo.app */, + 52FE63A01D3531B00050814B /* RMStoreDemo_OSX.app */, ); name = Products; sourceTree = ""; @@ -271,6 +334,8 @@ A0AF3D0A17A802F300D2E836 /* Frameworks */ = { isa = PBXGroup; children = ( + 52FE63BA1D3534450050814B /* Security.framework */, + 52FE63B81D3534390050814B /* StoreKit.framework */, C90EF0F019A20C8200A9E738 /* XCTest.framework */, A0AF3D3D17A807FF00D2E836 /* CoreGraphics.framework */, A0AF3D0B17A802F300D2E836 /* Foundation.framework */, @@ -362,6 +427,23 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 52FE639F1D3531B00050814B /* RMStoreDemo_OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 52FE63B31D3531B00050814B /* Build configuration list for PBXNativeTarget "RMStoreDemo_OSX" */; + buildPhases = ( + 52FE639C1D3531B00050814B /* Sources */, + 52FE639D1D3531B00050814B /* Frameworks */, + 52FE639E1D3531B00050814B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RMStoreDemo_OSX; + productName = RMStoreDemo_OSX; + productReference = 52FE63A01D3531B00050814B /* RMStoreDemo_OSX.app */; + productType = "com.apple.product-type.application"; + }; A0AF3D0717A802F300D2E836 /* RMStore */ = { isa = PBXNativeTarget; buildConfigurationList = A0AF3D2D17A802F300D2E836 /* Build configuration list for PBXNativeTarget "RMStore" */; @@ -422,6 +504,11 @@ attributes = { LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Robot Media"; + TargetAttributes = { + 52FE639F1D3531B00050814B = { + CreatedOnToolsVersion = 7.3; + }; + }; }; buildConfigurationList = A0AF3D0317A802F300D2E836 /* Build configuration list for PBXProject "RMStore" */; compatibilityVersion = "Xcode 3.2"; @@ -429,6 +516,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = A0AF3CFF17A802F300D2E836; productRefGroup = A0AF3D0917A802F300D2E836 /* Products */; @@ -438,11 +526,21 @@ A0AF3D0717A802F300D2E836 /* RMStore */, A0AF3D1817A802F300D2E836 /* RMStoreTests */, A0AF3D7117A8085900D2E836 /* RMStoreDemo */, + 52FE639F1D3531B00050814B /* RMStoreDemo_OSX */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 52FE639E1D3531B00050814B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 52FE63AC1D3531B00050814B /* Assets.xcassets in Resources */, + 52FE63AF1D3531B00050814B /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; A0AF3D1617A802F300D2E836 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -466,6 +564,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 52FE639C1D3531B00050814B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 52FE63BE1D3535A00050814B /* RMAppReceipt.m in Sources */, + 52FE63C01D3535A00050814B /* RMStoreAppReceiptVerifier.m in Sources */, + 52FE63C21D3535A00050814B /* RMStoreKeychainPersistence.m in Sources */, + 52FE63C41D3535A00050814B /* RMStoreTransaction.m in Sources */, + 52FE63C61D3535A00050814B /* RMStoreTransactionReceiptVerifier.m in Sources */, + 52FE63C81D3535A00050814B /* RMStoreUserDefaultsPersistence.m in Sources */, + 52FE63CA1D3535A00050814B /* RMStore.m in Sources */, + 52FE63AA1D3531B00050814B /* ViewController.m in Sources */, + 52FE63A71D3531B00050814B /* main.m in Sources */, + 52FE63A41D3531B00050814B /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; A0AF3D0417A802F300D2E836 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -524,6 +639,14 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 52FE63AD1D3531B00050814B /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 52FE63AE1D3531B00050814B /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; A0AF3D2517A802F300D2E836 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( @@ -543,6 +666,86 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 52FE63B11D3531B00050814B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "RMStore/Optional/openssl-1.0.1e/include", + ); + INFOPLIST_FILE = RMStoreDemo_OSX/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/RMStore/Optional/openssl-1.0.1e/lib", + ); + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = "net.robotmedia.RMStoreDemo-OSX"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + VALID_ARCHS = "i386 x86_64"; + }; + name = Debug; + }; + 52FE63B21D3531B00050814B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "RMStore/Optional/openssl-1.0.1e/include", + ); + INFOPLIST_FILE = RMStoreDemo_OSX/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/RMStore/Optional/openssl-1.0.1e/lib", + ); + MACOSX_DEPLOYMENT_TARGET = 10.11; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "net.robotmedia.RMStoreDemo-OSX"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + VALID_ARCHS = "i386 x86_64"; + }; + name = Release; + }; A0AF3D2B17A802F300D2E836 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -756,6 +959,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 52FE63B31D3531B00050814B /* Build configuration list for PBXNativeTarget "RMStoreDemo_OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 52FE63B11D3531B00050814B /* Debug */, + 52FE63B21D3531B00050814B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; A0AF3D0317A802F300D2E836 /* Build configuration list for PBXProject "RMStore" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 68aa7147..e3db35c9 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -19,7 +19,6 @@ // #import "RMAppReceipt.h" -#import #import #import #import @@ -101,6 +100,57 @@ static int RMASN1ReadInteger(const uint8_t **pp, long omax) return RMASN1ReadString(pp, omax, V_ASN1_IA5STRING, NSASCIIStringEncoding); } +// Returns a CFData object, containing the computer's GUID. +static CFDataRef copy_mac_address(void) +{ + kern_return_t kernResult; + mach_port_t master_port; + CFMutableDictionaryRef matchingDict; + io_iterator_t iterator; + io_object_t service; + CFDataRef macAddress = nil; + + kernResult = IOMasterPort(MACH_PORT_NULL, &master_port); + if (kernResult != KERN_SUCCESS) { + printf("IOMasterPort returned %d\n", kernResult); + return nil; + } + + matchingDict = IOBSDNameMatching(master_port, 0, "en0"); + if (!matchingDict) { + printf("IOBSDNameMatching returned empty dictionary\n"); + return nil; + } + + kernResult = IOServiceGetMatchingServices(master_port, matchingDict, &iterator); + if (kernResult != KERN_SUCCESS) { + printf("IOServiceGetMatchingServices returned %d\n", kernResult); + return nil; + } + + while((service = IOIteratorNext(iterator)) != 0) { + io_object_t parentService; + + kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, + &parentService); + if (kernResult == KERN_SUCCESS) { + if (macAddress) CFRelease(macAddress); + + macAddress = (CFDataRef) IORegistryEntryCreateCFProperty(parentService, + CFSTR("IOMACAddress"), kCFAllocatorDefault, 0); + IOObjectRelease(parentService); + } else { + printf("IORegistryEntryGetParentEntry returned %d\n", kernResult); + } + + IOObjectRelease(service); + } + IOObjectRelease(iterator); + + return macAddress; +} + + static NSURL *_appleRootCertificateURL = nil; @implementation RMAppReceipt @@ -187,6 +237,9 @@ - (BOOL)verifyReceiptHash // Order taken from: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW5 NSMutableData *data = [NSMutableData data]; [data appendBytes:uuidBytes length:sizeof(uuidBytes)]; + + [data appendData:(__bridge NSData * _Nonnull)(copy_mac_address())]; + [data appendData:self.opaqueValue]; [data appendData:self.bundleIdentifierData]; diff --git a/RMStore/Optional/RMStoreTransaction.h b/RMStore/Optional/RMStoreTransaction.h index d97d1394..92f6892e 100644 --- a/RMStore/Optional/RMStoreTransaction.h +++ b/RMStore/Optional/RMStoreTransaction.h @@ -27,9 +27,6 @@ @property(nonatomic, copy) NSString *productIdentifier; @property(nonatomic, copy) NSDate *transactionDate; @property(nonatomic, copy) NSString *transactionIdentifier; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 -@property(nonatomic, strong) NSData *transactionReceipt; -#endif - (instancetype)initWithPaymentTransaction:(SKPaymentTransaction*)paymentTransaction; diff --git a/RMStore/Optional/RMStoreTransaction.m b/RMStore/Optional/RMStoreTransaction.m index 6855809a..e22b2c98 100644 --- a/RMStore/Optional/RMStoreTransaction.m +++ b/RMStore/Optional/RMStoreTransaction.m @@ -24,9 +24,6 @@ NSString* const RMStoreCoderProductIdentifierKey = @"productIdentifier"; NSString* const RMStoreCoderTransactionDateKey = @"transactionDate"; NSString* const RMStoreCoderTransactionIdentifierKey = @"transactionIdentifier"; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 -NSString* const RMStoreCoderTransactionReceiptKey = @"transactionReceipt"; -#endif @implementation RMStoreTransaction @@ -37,9 +34,6 @@ - (instancetype)initWithPaymentTransaction:(SKPaymentTransaction*)paymentTransac _productIdentifier = paymentTransaction.payment.productIdentifier; _transactionDate = paymentTransaction.transactionDate; _transactionIdentifier = paymentTransaction.transactionIdentifier; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - _transactionReceipt = paymentTransaction.transactionReceipt; -#endif } return self; } @@ -52,9 +46,6 @@ - (instancetype)initWithCoder:(NSCoder *)decoder _productIdentifier = [decoder decodeObjectForKey:RMStoreCoderProductIdentifierKey]; _transactionDate = [decoder decodeObjectForKey:RMStoreCoderTransactionDateKey]; _transactionIdentifier = [decoder decodeObjectForKey:RMStoreCoderTransactionIdentifierKey]; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - _transactionReceipt = [decoder decodeObjectForKey:RMStoreCoderTransactionReceiptKey]; -#endif } return self; } @@ -64,10 +55,9 @@ - (void)encodeWithCoder:(NSCoder *)coder [coder encodeBool:self.consumed forKey:RMStoreCoderConsumedKey]; [coder encodeObject:self.productIdentifier forKey:RMStoreCoderProductIdentifierKey]; [coder encodeObject:self.transactionDate forKey:RMStoreCoderTransactionDateKey]; - if (self.transactionIdentifier != nil) { [coder encodeObject:self.transactionIdentifier forKey:RMStoreCoderTransactionIdentifierKey]; } -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - if (self.transactionReceipt != nil) { [coder encodeObject:self.transactionReceipt forKey:RMStoreCoderTransactionReceiptKey]; } -#endif + if (self.transactionIdentifier != nil) { + [coder encodeObject:self.transactionIdentifier forKey:RMStoreCoderTransactionIdentifierKey]; + } } @end diff --git a/RMStoreDemo_OSX/AppDelegate.h b/RMStoreDemo_OSX/AppDelegate.h new file mode 100644 index 00000000..af1ddca0 --- /dev/null +++ b/RMStoreDemo_OSX/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// RMStoreDemo_OSX +// +// Created by Sergey P on 12.07.16. +// Copyright © 2016 Robot Media. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/RMStoreDemo_OSX/AppDelegate.m b/RMStoreDemo_OSX/AppDelegate.m new file mode 100644 index 00000000..23e81077 --- /dev/null +++ b/RMStoreDemo_OSX/AppDelegate.m @@ -0,0 +1,34 @@ +// +// AppDelegate.m +// RMStoreDemo_OSX +// +// Created by Sergey P on 12.07.16. +// Copyright © 2016 Robot Media. All rights reserved. +// + +#import "AppDelegate.h" +#import "RMStore.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + // Insert code here to initialize your application + + NSSet *products = [NSSet setWithArray:@[@"fabulousIdol", @"rootBeer", @"rubberChicken"]]; + [[RMStore defaultStore] requestProducts:products success:^(NSArray *products, NSArray *invalidProductIdentifiers) { + NSLog(@"Products loaded"); + } failure:^(NSError *error) { + NSLog(@"Something went wrong"); + }]; +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + +@end diff --git a/RMStoreDemo_OSX/Assets.xcassets/AppIcon.appiconset/Contents.json b/RMStoreDemo_OSX/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..2db2b1c7 --- /dev/null +++ b/RMStoreDemo_OSX/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/RMStoreDemo_OSX/Base.lproj/Main.storyboard b/RMStoreDemo_OSX/Base.lproj/Main.storyboard new file mode 100644 index 00000000..2fa68bb1 --- /dev/null +++ b/RMStoreDemo_OSX/Base.lproj/Main.storyboard @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RMStoreDemo_OSX/Info.plist b/RMStoreDemo_OSX/Info.plist new file mode 100644 index 00000000..2b599d83 --- /dev/null +++ b/RMStoreDemo_OSX/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Robot Media. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + + diff --git a/RMStoreDemo_OSX/ViewController.h b/RMStoreDemo_OSX/ViewController.h new file mode 100644 index 00000000..153a10d9 --- /dev/null +++ b/RMStoreDemo_OSX/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// RMStoreDemo_OSX +// +// Created by Sergey P on 12.07.16. +// Copyright © 2016 Robot Media. All rights reserved. +// + +#import + +@interface ViewController : NSViewController + + +@end + diff --git a/RMStoreDemo_OSX/ViewController.m b/RMStoreDemo_OSX/ViewController.m new file mode 100644 index 00000000..1bc7429d --- /dev/null +++ b/RMStoreDemo_OSX/ViewController.m @@ -0,0 +1,25 @@ +// +// ViewController.m +// RMStoreDemo_OSX +// +// Created by Sergey P on 12.07.16. +// Copyright © 2016 Robot Media. All rights reserved. +// + +#import "ViewController.h" + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view. +} + +- (void)setRepresentedObject:(id)representedObject { + [super setRepresentedObject:representedObject]; + + // Update the view, if already loaded. +} + +@end diff --git a/RMStoreDemo_OSX/main.m b/RMStoreDemo_OSX/main.m new file mode 100644 index 00000000..7f6c0f9e --- /dev/null +++ b/RMStoreDemo_OSX/main.m @@ -0,0 +1,13 @@ +// +// main.m +// RMStoreDemo_OSX +// +// Created by Sergey P on 12.07.16. +// Copyright © 2016 Robot Media. All rights reserved. +// + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/RMStoreTests/RMStoreTransactionTests.m b/RMStoreTests/RMStoreTransactionTests.m index ada0aaba..fc571593 100644 --- a/RMStoreTests/RMStoreTransactionTests.m +++ b/RMStoreTests/RMStoreTransactionTests.m @@ -33,9 +33,7 @@ - (void)testInitWithPaymentTransaction XCTAssertEqualObjects(transaction.productIdentifier, payment.productIdentifier, @""); XCTAssertEqualObjects(transaction.transactionDate, paymentTransaction.transactionDate, @""); XCTAssertEqualObjects(transaction.transactionIdentifier, paymentTransaction.transactionIdentifier, @""); -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - XCTAssertEqualObjects(transaction.transactionReceipt, paymentTransaction.transactionReceipt, @""); -#endif + XCTAssertFalse(transaction.consumed, @""); } @@ -47,9 +45,7 @@ - (void)testCoding transaction.productIdentifier = @"test"; transaction.transactionDate = [NSDate date]; transaction.transactionIdentifier = @"transaction"; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - transaction.transactionReceipt = [NSData data]; -#endif + transaction.consumed = YES; NSMutableData *data = [[NSMutableData alloc] init]; @@ -65,9 +61,7 @@ - (void)testCoding XCTAssertEqualObjects(decodedTransaction.productIdentifier, transaction.productIdentifier, @""); XCTAssertEqualObjects(decodedTransaction.transactionDate, transaction.transactionDate, @""); XCTAssertEqualObjects(decodedTransaction.transactionIdentifier, transaction.transactionIdentifier, @""); -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - XCTAssertEqualObjects(decodedTransaction.transactionReceipt, transaction.transactionReceipt, @""); -#endif + XCTAssertEqual(decodedTransaction.consumed, transaction.consumed, @""); } @@ -78,9 +72,7 @@ - (SKPaymentTransaction*)mockPaymentTransactionOfProductIdentifer:(NSString*)pro id transaction = [OCMockObject mockForClass:[SKPaymentTransaction class]]; [[[transaction stub] andReturn:[NSDate date]] transactionDate]; [[[transaction stub] andReturn:@"transaction"] transactionIdentifier]; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - [[[transaction stub] andReturn:[NSData data]] transactionReceipt]; -#endif + id payment = [OCMockObject mockForClass:[SKPayment class]]; [[[payment stub] andReturn:productIdentifier] productIdentifier]; [[[transaction stub] andReturn:payment] payment]; diff --git a/RMStoreTests/RMStoreUserDefaultsPersistenceTests.m b/RMStoreTests/RMStoreUserDefaultsPersistenceTests.m index 3176049c..032c397b 100644 --- a/RMStoreTests/RMStoreUserDefaultsPersistenceTests.m +++ b/RMStoreTests/RMStoreUserDefaultsPersistenceTests.m @@ -202,9 +202,7 @@ - (void)compareTransaction:(RMStoreTransaction*)transaction1 withTransaction:(RM XCTAssertEqualObjects(transaction1.productIdentifier, transaction2.productIdentifier, @""); XCTAssertEqualObjects(transaction1.transactionDate, transaction2.transactionDate, @""); XCTAssertEqualObjects(transaction1.transactionIdentifier, transaction2.transactionIdentifier, @""); -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - XCTAssertEqualObjects(transaction1.transactionReceipt, transaction2.transactionReceipt, @""); -#endif + XCTAssertEqual(transaction1.consumed, transaction2.consumed, @""); } @@ -215,9 +213,7 @@ - (RMStoreTransaction*)sampleTransaction transaction.productIdentifier = @"test"; transaction.transactionDate = [NSDate date]; transaction.transactionIdentifier = @"transaction"; -#if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 - transaction.transactionReceipt = [NSData data]; -#endif + transaction.consumed = YES; return transaction; } From f882212e3387d3be50ba115fc1ad05095bf176b1 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sat, 6 Aug 2016 18:16:42 +0300 Subject: [PATCH 02/23] Remove old transaction verifier. --- RMStore.podspec | 1 - .../RMStoreTransactionReceiptVerifier.h | 27 --- .../RMStoreTransactionReceiptVerifier.m | 201 ------------------ 3 files changed, 229 deletions(-) delete mode 100644 RMStore/Optional/RMStoreTransactionReceiptVerifier.h delete mode 100644 RMStore/Optional/RMStoreTransactionReceiptVerifier.m diff --git a/RMStore.podspec b/RMStore.podspec index 6f8905df..f376781d 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -31,7 +31,6 @@ Pod::Spec.new do |s| s.subspec 'AppReceiptVerifier' do |arv| arv.dependency 'RMStore/Core' - arv.platform = :ios, '7.0' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' arv.dependency 'OpenSSL', '~> 1.0' end diff --git a/RMStore/Optional/RMStoreTransactionReceiptVerifier.h b/RMStore/Optional/RMStoreTransactionReceiptVerifier.h deleted file mode 100644 index 3418ed67..00000000 --- a/RMStore/Optional/RMStoreTransactionReceiptVerifier.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// RMStoreTransactionReceiptVerifier.h -// RMStore -// -// Created by Hermes Pique on 7/31/13. -// Copyright (c) 2013 Robot Media SL (http://www.robotmedia.net) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import -#import "RMStore.h" - -__attribute__((availability(ios,deprecated=7.0))) -@interface RMStoreTransactionReceiptVerifier : NSObject - -@end diff --git a/RMStore/Optional/RMStoreTransactionReceiptVerifier.m b/RMStore/Optional/RMStoreTransactionReceiptVerifier.m deleted file mode 100644 index e7e06359..00000000 --- a/RMStore/Optional/RMStoreTransactionReceiptVerifier.m +++ /dev/null @@ -1,201 +0,0 @@ -// -// RMStoreTransactionReceiptVerifier.m -// RMStore -// -// Created by Hermes Pique on 7/31/13. -// Copyright (c) 2013 Robot Media SL (http://www.robotmedia.net) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#import "RMStoreTransactionReceiptVerifier.h" - -#ifdef DEBUG -#define RMStoreLog(...) NSLog(@"RMStore: %@", [NSString stringWithFormat:__VA_ARGS__]); -#else -#define RMStoreLog(...) -#endif - -@interface NSData(rm_base64) - -- (NSString *)rm_stringByBase64Encoding; - -@end - -@implementation NSData(rm_base64) - -static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -- (NSString *)rm_stringByBase64Encoding -{ // From: http://stackoverflow.com/a/4727124/143378 - const unsigned char * objRawData = self.bytes; - char * objPointer; - char * strResult; - - // Get the Raw Data length and ensure we actually have data - NSInteger intLength = self.length; - if (intLength == 0) return nil; - - // Setup the String-based Result placeholder and pointer within that placeholder - strResult = (char *)calloc((((intLength + 2) / 3) * 4) + 1, sizeof(char)); - objPointer = strResult; - - // Iterate through everything - while (intLength > 2) { // keep going until we have less than 24 bits - *objPointer++ = _base64EncodingTable[objRawData[0] >> 2]; - *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]; - *objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)]; - *objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f]; - - // we just handled 3 octets (24 bits) of data - objRawData += 3; - intLength -= 3; - } - - // now deal with the tail end of things - if (intLength != 0) { - *objPointer++ = _base64EncodingTable[objRawData[0] >> 2]; - if (intLength > 1) { - *objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]; - *objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2]; - *objPointer++ = '='; - } else { - *objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4]; - *objPointer++ = '='; - *objPointer++ = '='; - } - } - - // Terminate the string-based result - *objPointer = '\0'; - - // Create result NSString object - NSString *base64String = @(strResult); - - // Free memory - free(strResult); - - return base64String; -} - -@end - - -@implementation RMStoreTransactionReceiptVerifier - -- (void)verifyTransaction:(SKPaymentTransaction*)transaction - success:(void (^)())successBlock - failure:(void (^)(NSError *error))failureBlock -{ - NSString *receipt = [transaction.transactionReceipt rm_stringByBase64Encoding]; - if (receipt == nil) - { - if (failureBlock != nil) - { - NSError *error = [NSError errorWithDomain:RMStoreErrorDomain code:0 userInfo:nil]; - failureBlock(error); - } - return; - } - static NSString *receiptDataKey = @"receipt-data"; - NSDictionary *jsonReceipt = @{receiptDataKey : receipt}; - - NSError *error; - NSData *requestData = [NSJSONSerialization dataWithJSONObject:jsonReceipt options:0 error:&error]; - if (!requestData) - { - RMStoreLog(@"Failed to serialize receipt into JSON"); - if (failureBlock != nil) - { - failureBlock(error); - } - return; - } - - static NSString *productionURL = @"https://buy.itunes.apple.com/verifyReceipt"; - - [self verifyRequestData:requestData url:productionURL success:successBlock failure:failureBlock]; -} - -- (void)verifyRequestData:(NSData*)requestData - url:(NSString*)urlString - success:(void (^)())successBlock - failure:(void (^)(NSError *error))failureBlock -{ - NSURL *url = [NSURL URLWithString:urlString]; - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.HTTPBody = requestData; - static NSString *requestMethod = @"POST"; - request.HTTPMethod = requestMethod; - - dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSError *error; - NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error]; - dispatch_async(dispatch_get_main_queue(), ^{ - if (!data) - { - RMStoreLog(@"Server Connection Failed"); - NSError *wrapperError = [NSError errorWithDomain:RMStoreErrorDomain code:RMStoreErrorCodeUnableToCompleteVerification userInfo:@{NSUnderlyingErrorKey : error, NSLocalizedDescriptionKey : NSLocalizedStringFromTable(@"Connection to Apple failed. Check the underlying error for more info.", @"RMStore", @"Error description")}]; - if (failureBlock != nil) - { - failureBlock(wrapperError); - } - return; - } - NSError *jsonError; - NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; - if (!responseJSON) - { - RMStoreLog(@"Failed To Parse Server Response"); - if (failureBlock != nil) - { - failureBlock(jsonError); - } - } - - static NSString *statusKey = @"status"; - NSInteger statusCode = [responseJSON[statusKey] integerValue]; - - static NSInteger successCode = 0; - static NSInteger sandboxCode = 21007; - if (statusCode == successCode) - { - if (successBlock != nil) - { - successBlock(); - } - } - else if (statusCode == sandboxCode) - { - RMStoreLog(@"Verifying Sandbox Receipt"); - // From: https://developer.apple.com/library/ios/#technotes/tn2259/_index.html - // See also: http://stackoverflow.com/questions/9677193/ios-storekit-can-i-detect-when-im-in-the-sandbox - // Always verify your receipt first with the production URL; proceed to verify with the sandbox URL if you receive a 21007 status code. Following this approach ensures that you do not have to switch between URLs while your application is being tested or reviewed in the sandbox or is live in the App Store. - - static NSString *sandboxURL = @"https://sandbox.itunes.apple.com/verifyReceipt"; - [self verifyRequestData:requestData url:sandboxURL success:successBlock failure:failureBlock]; - } - else - { - RMStoreLog(@"Verification Failed With Code %ld", (long)statusCode); - NSError *serverError = [NSError errorWithDomain:RMStoreErrorDomain code:statusCode userInfo:nil]; - if (failureBlock != nil) - { - failureBlock(serverError); - } - } - }); - }); -} - -@end From e73584d84149063be84e23e92596d463b8749efa Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sat, 6 Aug 2016 18:17:02 +0300 Subject: [PATCH 03/23] Remove from project files. --- RMStore.xcodeproj/project.pbxproj | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/RMStore.xcodeproj/project.pbxproj b/RMStore.xcodeproj/project.pbxproj index ebc91994..7d46e1f9 100644 --- a/RMStore.xcodeproj/project.pbxproj +++ b/RMStore.xcodeproj/project.pbxproj @@ -20,7 +20,6 @@ 52FE63C01D3535A00050814B /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; 52FE63C21D3535A00050814B /* RMStoreKeychainPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 876046481812FB7500C9B78C /* RMStoreKeychainPersistence.m */; }; 52FE63C41D3535A00050814B /* RMStoreTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 876631F8180EEBF40049B368 /* RMStoreTransaction.m */; }; - 52FE63C61D3535A00050814B /* RMStoreTransactionReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */; }; 52FE63C81D3535A00050814B /* RMStoreUserDefaultsPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 87A2A3A8180E82BB00376773 /* RMStoreUserDefaultsPersistence.m */; }; 52FE63CA1D3535A00050814B /* RMStore.m in Sources */ = {isa = PBXBuildFile; fileRef = A0AF3D1217A802F300D2E836 /* RMStore.m */; }; 8700D1C117DCA548005C8F5D /* NSNotification+RMStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8700D1C017DCA548005C8F5D /* NSNotification+RMStoreTests.m */; }; @@ -30,7 +29,6 @@ 8760464D18130DD400C9B78C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8760464C18130DD400C9B78C /* Security.framework */; }; 8760464E18130DD800C9B78C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8760464C18130DD400C9B78C /* Security.framework */; }; 8760465018131B2600C9B78C /* RMStoreKeychainPersistence.m in Sources */ = {isa = PBXBuildFile; fileRef = 876046481812FB7500C9B78C /* RMStoreKeychainPersistence.m */; }; - 8760465118131B4800C9B78C /* RMStoreTransactionReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */; }; 876631F9180EEBF40049B368 /* RMStoreTransaction.m in Sources */ = {isa = PBXBuildFile; fileRef = 876631F8180EEBF40049B368 /* RMStoreTransaction.m */; }; 8793E799180C2ABE005D7A66 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8793E797180C2ABE005D7A66 /* libcrypto.a */; }; 8793E79A180C2ABE005D7A66 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8793E798180C2ABE005D7A66 /* libssl.a */; }; @@ -38,7 +36,6 @@ 8793E79E180C2C90005D7A66 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8793E797180C2ABE005D7A66 /* libcrypto.a */; }; 8793E808180D512E005D7A66 /* RMAppReceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E801180D512E005D7A66 /* RMAppReceipt.m */; }; 8793E809180D512E005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; - 8793E80A180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */; }; 8793E80B180D5133005D7A66 /* RMAppReceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E801180D512E005D7A66 /* RMAppReceipt.m */; }; 8793E80C180D5136005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; 87950C2317E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 87950C2217E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m */; }; @@ -131,8 +128,6 @@ 8793E801180D512E005D7A66 /* RMAppReceipt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAppReceipt.m; sourceTree = ""; }; 8793E802180D512E005D7A66 /* RMStoreAppReceiptVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMStoreAppReceiptVerifier.h; sourceTree = ""; }; 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMStoreAppReceiptVerifier.m; sourceTree = ""; }; - 8793E804180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMStoreTransactionReceiptVerifier.h; sourceTree = ""; }; - 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMStoreTransactionReceiptVerifier.m; sourceTree = ""; }; 87950C2217E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMStoreTransactionReceiptVerifierTests.m; sourceTree = ""; }; 87A2A39F180D7B0400376773 /* RMAppReceiptTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAppReceiptTests.m; sourceTree = ""; }; 87A2A3A1180D7E2900376773 /* RMStoreTests-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RMStoreTests-Prefix.pch"; sourceTree = ""; }; @@ -300,8 +295,6 @@ 876046481812FB7500C9B78C /* RMStoreKeychainPersistence.m */, 876631F7180EEBF40049B368 /* RMStoreTransaction.h */, 876631F8180EEBF40049B368 /* RMStoreTransaction.m */, - 8793E804180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.h */, - 8793E805180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m */, 87A2A3A7180E82BB00376773 /* RMStoreUserDefaultsPersistence.h */, 87A2A3A8180E82BB00376773 /* RMStoreUserDefaultsPersistence.m */, ); @@ -572,7 +565,6 @@ 52FE63C01D3535A00050814B /* RMStoreAppReceiptVerifier.m in Sources */, 52FE63C21D3535A00050814B /* RMStoreKeychainPersistence.m in Sources */, 52FE63C41D3535A00050814B /* RMStoreTransaction.m in Sources */, - 52FE63C61D3535A00050814B /* RMStoreTransactionReceiptVerifier.m in Sources */, 52FE63C81D3535A00050814B /* RMStoreUserDefaultsPersistence.m in Sources */, 52FE63CA1D3535A00050814B /* RMStore.m in Sources */, 52FE63AA1D3531B00050814B /* ViewController.m in Sources */, @@ -587,7 +579,6 @@ files = ( A0AF3D1317A802F300D2E836 /* RMStore.m in Sources */, 876046491812FB7500C9B78C /* RMStoreKeychainPersistence.m in Sources */, - 8793E80A180D512E005D7A66 /* RMStoreTransactionReceiptVerifier.m in Sources */, 8793E809180D512E005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */, 87A2A3A9180E82BB00376773 /* RMStoreUserDefaultsPersistence.m in Sources */, 8793E808180D512E005D7A66 /* RMAppReceipt.m in Sources */, @@ -622,7 +613,6 @@ A0AF3DA217A8094600D2E836 /* RMStoreViewController.m in Sources */, 8793E80C180D5136005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */, A0AF3DA717A8095F00D2E836 /* RMPurchasesViewController.m in Sources */, - 8760465118131B4800C9B78C /* RMStoreTransactionReceiptVerifier.m in Sources */, A0AF3DA917A80B2F00D2E836 /* RMStore.m in Sources */, 8793E80B180D5133005D7A66 /* RMAppReceipt.m in Sources */, ); From 3a14eb09568ba7b8b66568b0718a29f29ea7635e Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sat, 6 Aug 2016 18:37:08 +0300 Subject: [PATCH 04/23] Remove unused attribute. --- RMStore/Optional/RMAppReceipt.h | 1 - 1 file changed, 1 deletion(-) diff --git a/RMStore/Optional/RMAppReceipt.h b/RMStore/Optional/RMAppReceipt.h index 9b45fe33..1eb05727 100644 --- a/RMStore/Optional/RMAppReceipt.h +++ b/RMStore/Optional/RMAppReceipt.h @@ -22,7 +22,6 @@ /** Represents the app receipt. */ -__attribute__((availability(ios,introduced=7.0))) @interface RMAppReceipt : NSObject /** The app’s bundle identifier. From 2043b013a22336ae2d054a150feb9983fc27e0d0 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sun, 7 Aug 2016 15:07:20 +0300 Subject: [PATCH 05/23] Modify to validate the data for mac os. --- RMStore/Optional/RMAppReceipt.m | 16 +++++++++++----- RMStore/Optional/RMStoreAppReceiptVerifier.h | 1 - RMStore/RMStore.m | 9 ++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index e3db35c9..a01dcbd7 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -24,6 +24,10 @@ #import #import +#if TARGET_OS_IPHONE +#import +#endif + // From https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1 NSInteger const RMAppReceiptASN1TypeBundleIdentifier = 2; NSInteger const RMAppReceiptASN1TypeAppVersion = 3; @@ -150,7 +154,6 @@ static CFDataRef copy_mac_address(void) return macAddress; } - static NSURL *_appleRootCertificateURL = nil; @implementation RMAppReceipt @@ -230,15 +233,18 @@ -(BOOL)containsActiveAutoRenewableSubscriptionOfProductIdentifier:(NSString *)pr - (BOOL)verifyReceiptHash { // TODO: Getting the uuid in Mac is different. See: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW5 - NSUUID *uuid = [UIDevice currentDevice].identifierForVendor; - unsigned char uuidBytes[16]; - [uuid getUUIDBytes:uuidBytes]; // Order taken from: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW5 + NSMutableData *data = [NSMutableData data]; +#if TARGET_OS_IPHONE + NSUUID *uuid = [UIDevice currentDevice].identifierForVendor; + unsigned char uuidBytes[16]; + [uuid getUUIDBytes:uuidBytes]; [data appendBytes:uuidBytes length:sizeof(uuidBytes)]; - +#elif TARGET_OS_MAC [data appendData:(__bridge NSData * _Nonnull)(copy_mac_address())]; +#endif [data appendData:self.opaqueValue]; [data appendData:self.bundleIdentifierData]; diff --git a/RMStore/Optional/RMStoreAppReceiptVerifier.h b/RMStore/Optional/RMStoreAppReceiptVerifier.h index 204c15f2..e7c58239 100644 --- a/RMStore/Optional/RMStoreAppReceiptVerifier.h +++ b/RMStore/Optional/RMStoreAppReceiptVerifier.h @@ -24,7 +24,6 @@ /** Reference implementation of an app receipt verifier. If security is a concern you might want to avoid using a verifier whose code is open source. */ -__attribute__((availability(ios,introduced=7.0))) @interface RMStoreAppReceiptVerifier : NSObject /** diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index ece43bd9..e18d47e0 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -278,7 +278,6 @@ - (void)restoreTransactionsOfUser:(NSString*)userIdentifier + (NSURL*)receiptURL { // The general best practice of weak linking using the respondsToSelector: method cannot be used here. Prior to iOS 7, the method was implemented as private API, but that implementation called the doesNotRecognizeSelector: method. - NSAssert(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1, @"appStoreReceiptURL not supported in this iOS version."); NSURL *url = [NSBundle mainBundle].appStoreReceiptURL; return url; } @@ -416,7 +415,11 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloa { for (SKDownload *download in downloads) { +#if TARGET_OS_IPHONE switch (download.downloadState) +#elif TARGET_OS_MAC + switch (download.state) +#endif { case SKDownloadStateActive: [self didUpdateDownload:download queue:queue]; @@ -505,7 +508,11 @@ + (BOOL)hasPendingDownloadsInTransaction:(SKPaymentTransaction*)transaction { for (SKDownload *download in transaction.downloads) { +#if TARGET_OS_IPHONE switch (download.downloadState) +#elif TARGET_OS_MAC + switch (download.state) +#endif { case SKDownloadStateActive: case SKDownloadStatePaused: From 111595531c4bd62b19559ccaf079cf51185c35df Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sun, 7 Aug 2016 17:13:59 +0300 Subject: [PATCH 06/23] Remove unused __attribute__. --- RMStore/RMStore.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/RMStore/RMStore.h b/RMStore/RMStore.h index 1a7a6622..7eb65f71 100755 --- a/RMStore/RMStore.h +++ b/RMStore/RMStore.h @@ -76,7 +76,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; - (void)addPayment:(NSString*)productIdentifier user:(NSString*)userIdentifier success:(void (^)(SKPaymentTransaction *transaction))successBlock - failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock __attribute__((availability(ios,introduced=7.0))); + failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock; /** Request localized information about a set of products from the Apple App Store. @param identifiers The set of product identifiers for the products you wish to retrieve information of. @@ -111,7 +111,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; */ - (void)restoreTransactionsOfUser:(NSString*)userIdentifier onSuccess:(void (^)(NSArray *transactions))successBlock - failure:(void (^)(NSError *error))failureBlock __attribute__((availability(ios,introduced=7.0))); + failure:(void (^)(NSError *error))failureBlock; #pragma mark Receipt ///--------------------------------------------- @@ -122,18 +122,18 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; If this method returns `nil` you should refresh the receipt by calling `refreshReceipt`. @see refreshReceipt */ -+ (NSURL*)receiptURL __attribute__((availability(ios,introduced=7.0))); ++ (NSURL*)receiptURL; /** Request to refresh the App Store receipt in case the receipt is invalid or missing. */ -- (void)refreshReceipt __attribute__((availability(ios,introduced=7.0))); +- (void)refreshReceipt; /** Request to refresh the App Store receipt in case the receipt is invalid or missing. `successBlock` will be called if the refresh receipt request is successful, `failureBlock` if it isn't. @param successBlock The block to be called if the refresh receipt request is sucessful. Can be `nil`. @param failureBlock The block to be called if the refresh receipt request fails. Can be `nil`. */ - (void)refreshReceiptOnSuccess:(void (^)())successBlock - failure:(void (^)(NSError *error))failureBlock __attribute__((availability(ios,introduced=7.0))); + failure:(void (^)(NSError *error))failureBlock; ///--------------------------------------------- /// @name Setting Delegates @@ -229,36 +229,36 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; Tells the observer that a download has been canceled. @discussion Only for Apple-hosted downloads. */ -- (void)storeDownloadCanceled:(NSNotification*)notification __attribute__((availability(ios,introduced=6.0))); +- (void)storeDownloadCanceled:(NSNotification*)notification; /** Tells the observer that a download has failed. Use @c storeError to get the cause. */ -- (void)storeDownloadFailed:(NSNotification*)notification __attribute__((availability(ios,introduced=6.0))); +- (void)storeDownloadFailed:(NSNotification*)notification; /** Tells the observer that a download has finished. */ -- (void)storeDownloadFinished:(NSNotification*)notification __attribute__((availability(ios,introduced=6.0))); +- (void)storeDownloadFinished:(NSNotification*)notification; /** Tells the observer that a download has been paused. @discussion Only for Apple-hosted downloads. */ -- (void)storeDownloadPaused:(NSNotification*)notification __attribute__((availability(ios,introduced=6.0))); +- (void)storeDownloadPaused:(NSNotification*)notification; /** Tells the observer that a download has been updated. Use @c downloadProgress to get the progress. */ -- (void)storeDownloadUpdated:(NSNotification*)notification __attribute__((availability(ios,introduced=6.0))); +- (void)storeDownloadUpdated:(NSNotification*)notification; - (void)storePaymentTransactionDeferred:(NSNotification*)notification __attribute__((availability(ios,introduced=8.0))); - (void)storePaymentTransactionFailed:(NSNotification*)notification; - (void)storePaymentTransactionFinished:(NSNotification*)notification; - (void)storeProductsRequestFailed:(NSNotification*)notification; - (void)storeProductsRequestFinished:(NSNotification*)notification; -- (void)storeRefreshReceiptFailed:(NSNotification*)notification __attribute__((availability(ios,introduced=7.0))); -- (void)storeRefreshReceiptFinished:(NSNotification*)notification __attribute__((availability(ios,introduced=7.0))); +- (void)storeRefreshReceiptFailed:(NSNotification*)notification; +- (void)storeRefreshReceiptFinished:(NSNotification*)notification; - (void)storeRestoreTransactionsFailed:(NSNotification*)notification; - (void)storeRestoreTransactionsFinished:(NSNotification*)notification; @@ -291,7 +291,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; /** Used in @c storeDownload*:. */ -@property (nonatomic, readonly) SKDownload *rm_storeDownload __attribute__((availability(ios,introduced=6.0))); +@property (nonatomic, readonly) SKDownload *rm_storeDownload; /** Used in @c storeDownloadFailed:, @c storePaymentTransactionFailed:, @c storeProductsRequestFailed:, @c storeRefreshReceiptFailed: and @c storeRestoreTransactionsFailed:. */ From 098b868feafd491add3c992753de9f1aad7ad530 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Sun, 7 Aug 2016 17:14:47 +0300 Subject: [PATCH 07/23] Changed subspec for the adding apple cert. --- RMStore.podspec | 1 + RMStore/Optional/RMAppReceipt.m | 1 + 2 files changed, 2 insertions(+) diff --git a/RMStore.podspec b/RMStore.podspec index f376781d..fe9a4f91 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -33,6 +33,7 @@ Pod::Spec.new do |s| arv.dependency 'RMStore/Core' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' arv.dependency 'OpenSSL', '~> 1.0' + arv.resources = 'RMStore/Optional/AppleIncRootCertificate.cer' end s.subspec 'TransactionReceiptVerifier' do |trv| diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index a01dcbd7..20966a8c 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -289,6 +289,7 @@ + (NSData*)dataFromPCKS7Path:(NSString*)path NSData *data; NSURL *certificateURL = _appleRootCertificateURL ? : [[NSBundle mainBundle] URLForResource:@"AppleIncRootCertificate" withExtension:@"cer"]; + NSAssert(certificateURL != nil, @"Certificate AppleIncRootCertificate.cer is missed, add it to the bundle"); NSData *certificateData = [NSData dataWithContentsOfURL:certificateURL]; if (!certificateData || [self verifyPCKS7:p7 withCertificateData:certificateData]) { From cd9c8effbf4dddb7f3538474f0dfe5c6cb9b2170 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 13:52:54 +0300 Subject: [PATCH 08/23] Remove deprecated pod spec. --- RMStore.podspec | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/RMStore.podspec b/RMStore.podspec index fe9a4f91..50379963 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -33,12 +33,8 @@ Pod::Spec.new do |s| arv.dependency 'RMStore/Core' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' arv.dependency 'OpenSSL', '~> 1.0' + arv.frameworks = 'Security' arv.resources = 'RMStore/Optional/AppleIncRootCertificate.cer' end - s.subspec 'TransactionReceiptVerifier' do |trv| - trv.dependency 'RMStore/Core' - trv.source_files = 'RMStore/Optional/RMStoreTransactionReceiptVerifier.{h,m}' - end - end From 995e44e4faf2ae322efadd670b19d24a99908d19 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 13:53:46 +0300 Subject: [PATCH 09/23] Added private mark to ivars. --- RMStore/RMStore.m | 1 + 1 file changed, 1 insertion(+) diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index e18d47e0..1d57298a 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -130,6 +130,7 @@ @interface RMStore() @end @implementation RMStore { +@private NSMutableDictionary *_addPaymentParameters; // HACK: We use a dictionary of product identifiers because the returned SKPayment is different from the one we add to the queue. Bad Apple. NSMutableDictionary *_products; NSMutableSet *_productsRequestDelegates; From f2353abaca3c4c4bbceb4e46d62ab01aacdc8c72 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 13:58:25 +0300 Subject: [PATCH 10/23] Added singleton for the keychain persistence. --- RMStore/Optional/RMStoreKeychainPersistence.h | 4 ++++ RMStore/Optional/RMStoreKeychainPersistence.m | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/RMStore/Optional/RMStoreKeychainPersistence.h b/RMStore/Optional/RMStoreKeychainPersistence.h index 31f9ca86..6dc8364f 100644 --- a/RMStore/Optional/RMStoreKeychainPersistence.h +++ b/RMStore/Optional/RMStoreKeychainPersistence.h @@ -25,6 +25,10 @@ */ @interface RMStoreKeychainPersistence : NSObject +/** Returns the singleton store instance. + */ ++ (RMStoreKeychainPersistence*)defaultPersistence; + /** Remove all persisted transactions from the keychain. */ - (void)removeTransactions; diff --git a/RMStore/Optional/RMStoreKeychainPersistence.m b/RMStore/Optional/RMStoreKeychainPersistence.m index 54195b3b..9460e5e2 100644 --- a/RMStore/Optional/RMStoreKeychainPersistence.m +++ b/RMStore/Optional/RMStoreKeychainPersistence.m @@ -84,9 +84,22 @@ void RMKeychainSetValue(NSData *value, NSString *key) } @implementation RMStoreKeychainPersistence { +@private NSDictionary *_transactionsDictionary; } +#pragma mark - Lifecycle + ++ (RMStoreKeychainPersistence *)defaultPersistence +{ + static RMStoreKeychainPersistence *_defaultPersistence = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _defaultPersistence = [[RMStoreKeychainPersistence alloc] init]; + }); + return _defaultPersistence; +} + #pragma mark - RMStoreTransactionPersistor - (void)persistTransaction:(SKPaymentTransaction*)paymentTransaction From 38c95e65f0b8d961491fae1e1f33fddd49a5397b Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 14:01:56 +0300 Subject: [PATCH 11/23] Added logs only for development at RMStoreKeychainPersistence --- RMStore/Optional/RMStoreKeychainPersistence.m | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/RMStore/Optional/RMStoreKeychainPersistence.m b/RMStore/Optional/RMStoreKeychainPersistence.m index 9460e5e2..26cf69ee 100644 --- a/RMStore/Optional/RMStoreKeychainPersistence.m +++ b/RMStore/Optional/RMStoreKeychainPersistence.m @@ -21,6 +21,13 @@ #import "RMStoreKeychainPersistence.h" #import +#if DEBUG +#define RMStoreKeychainPersistenceLog(...) NSLog(@"RMStoreKeychainPersistence: %@", [NSString stringWithFormat:__VA_ARGS__]); +#else +#define RMStoreKeychainPersistenceLog(...) +#endif + + NSString* const RMStoreTransactionsKeychainKey = @"RMStoreTransactions"; #pragma mark - Keychain @@ -64,7 +71,7 @@ void RMKeychainSetValue(NSData *value, NSString *key) } if (status != errSecSuccess) { - NSLog(@"RMStoreKeychainPersistence: failed to set key %@ with error %ld.", key, (long)status); + RMStoreKeychainPersistenceLog(@"failed to set key %@ with error %ld.", key, (long)status); } } @@ -78,7 +85,7 @@ void RMKeychainSetValue(NSData *value, NSString *key) OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&value); if (status != errSecSuccess && status != errSecItemNotFound) { - NSLog(@"RMStoreKeychainPersistence: failed to get key %@ with error %ld.", key, (long)status); + RMStoreKeychainPersistenceLog(@"failed to get key %@ with error %ld.", key, (long)status); } return (__bridge NSData*)value; } @@ -171,7 +178,7 @@ - (NSDictionary*)transactionsDictionary transactions = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (!transactions) { - NSLog(@"RMStoreKeychainPersistence: failed to read JSON data with error %@", error); + RMStoreKeychainPersistenceLog(@"failed to read JSON data with error %@", error); } } _transactionsDictionary = transactions; @@ -190,7 +197,7 @@ - (void)setTransactionsDictionary:(NSDictionary*)dictionary data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error]; if (!data) { - NSLog(@"RMStoreKeychainPersistence: failed to write JSON data with error %@", error); + RMStoreKeychainPersistenceLog(@"failed to write JSON data with error %@", error); } } RMKeychainSetValue(data, RMStoreTransactionsKeychainKey); From 0c2b7b4a26a7b7b3ca05f0ebb36f516e126a7555 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 16:49:36 +0300 Subject: [PATCH 12/23] Changed OS X receipt validation. Get the cert from keychain in OS X. --- RMStore/Optional/RMAppReceipt.m | 108 ++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 20966a8c..9de3a48a 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -26,6 +26,14 @@ #if TARGET_OS_IPHONE #import +#elif TARGET_OS_MAC +#import +#endif + +#if DEBUG +#define RMAppReceiptLog(...) NSLog(@"RMAppReceipt: %@", [NSString stringWithFormat:__VA_ARGS__]); +#else +#define RMAppReceiptLog(...) #endif // From https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1 @@ -104,8 +112,10 @@ static int RMASN1ReadInteger(const uint8_t **pp, long omax) return RMASN1ReadString(pp, omax, V_ASN1_IA5STRING, NSASCIIStringEncoding); } +#if TARGET_OS_MAC + // Returns a CFData object, containing the computer's GUID. -static CFDataRef copy_mac_address(void) +static CFDataRef CopyMACAddressData() { kern_return_t kernResult; mach_port_t master_port; @@ -116,19 +126,19 @@ static CFDataRef copy_mac_address(void) kernResult = IOMasterPort(MACH_PORT_NULL, &master_port); if (kernResult != KERN_SUCCESS) { - printf("IOMasterPort returned %d\n", kernResult); + RMAppReceiptLog(@"IOMasterPort returned %d", kernResult); return nil; } matchingDict = IOBSDNameMatching(master_port, 0, "en0"); if (!matchingDict) { - printf("IOBSDNameMatching returned empty dictionary\n"); + RMAppReceiptLog(@"IOBSDNameMatching returned empty dictionary"); return nil; } kernResult = IOServiceGetMatchingServices(master_port, matchingDict, &iterator); if (kernResult != KERN_SUCCESS) { - printf("IOServiceGetMatchingServices returned %d\n", kernResult); + RMAppReceiptLog(@"IOServiceGetMatchingServices returned %d", kernResult); return nil; } @@ -144,7 +154,7 @@ static CFDataRef copy_mac_address(void) CFSTR("IOMACAddress"), kCFAllocatorDefault, 0); IOObjectRelease(parentService); } else { - printf("IORegistryEntryGetParentEntry returned %d\n", kernResult); + RMAppReceiptLog(@"IORegistryEntryGetParentEntry returned %d", kernResult); } IOObjectRelease(service); @@ -154,6 +164,62 @@ static CFDataRef copy_mac_address(void) return macAddress; } +static inline SecCertificateRef AppleRootCAFromKeychain( void ) +{ + SecKeychainRef roots = NULL; + SecKeychainSearchRef search = NULL; + SecCertificateRef cert = NULL; + BOOL cfReleaseKeychain = YES; + + // there's a GC bug with this guy it seems + OSStatus err = SecKeychainOpen( "/System/Library/Keychains/SystemRootCertificates.keychain", &roots ); + + if ( err != noErr ) + { + CFStringRef errStr = SecCopyErrorMessageString( err, NULL ); + RMAppReceiptLog( @"Error: %d (%@)", err, errStr ); + CFRelease( errStr ); + return NULL; + } + + SecKeychainAttribute labelAttr = { .tag = kSecLabelItemAttr, .length = 13, .data = (void *)"Apple Root CA" }; + SecKeychainAttributeList attrs = { .count = 1, .attr = &labelAttr }; + + err = SecKeychainSearchCreateFromAttributes( roots, kSecCertificateItemClass, &attrs, &search ); + if ( err != noErr ) + { + CFStringRef errStr = SecCopyErrorMessageString( err, NULL ); + RMAppReceiptLog( @"Error: %d (%@)", err, errStr ); + CFRelease( errStr ); + if ( cfReleaseKeychain ) + CFRelease( roots ); + return NULL; + } + + SecKeychainItemRef item = NULL; + err = SecKeychainSearchCopyNext( search, &item ); + if ( err != noErr ) + { + CFStringRef errStr = SecCopyErrorMessageString( err, NULL ); + RMAppReceiptLog( @"Error: %d (%@)", err, errStr ); + CFRelease( errStr ); + if ( cfReleaseKeychain ) + CFRelease( roots ); + + return NULL; + } + + cert = (SecCertificateRef)item; + CFRelease( search ); + + if ( cfReleaseKeychain ) + CFRelease( roots ); + + return ( cert ); +} + +#endif + static NSURL *_appleRootCertificateURL = nil; @implementation RMAppReceipt @@ -243,7 +309,7 @@ - (BOOL)verifyReceiptHash [uuid getUUIDBytes:uuidBytes]; [data appendBytes:uuidBytes length:sizeof(uuidBytes)]; #elif TARGET_OS_MAC - [data appendData:(__bridge NSData * _Nonnull)(copy_mac_address())]; + [data appendData:(__bridge NSData * _Nonnull)(CopyMACAddressData())]; #endif [data appendData:self.opaqueValue]; @@ -287,11 +353,30 @@ + (NSData*)dataFromPCKS7Path:(NSString*)path if (!p7) return nil; - NSData *data; + NSData *certificateData = nil; +#if TARGET_OS_IPHONE NSURL *certificateURL = _appleRootCertificateURL ? : [[NSBundle mainBundle] URLForResource:@"AppleIncRootCertificate" withExtension:@"cer"]; - NSAssert(certificateURL != nil, @"Certificate AppleIncRootCertificate.cer is missed, add it to the bundle"); - NSData *certificateData = [NSData dataWithContentsOfURL:certificateURL]; - if (!certificateData || [self verifyPCKS7:p7 withCertificateData:certificateData]) + certificateData = [NSData dataWithContentsOfURL:certificateURL]; +#elif TARGET_OS_MAC + if (_appleRootCertificateURL) + { + certificateData = [NSData dataWithContentsOfURL:_appleRootCertificateURL]; + } + else + { + // get the Apple root CA from http://www.apple.com/certificateauthority and load it into b_X509 + //NSData * root = [NSData dataWithContentsOfURL: [NSURL URLWithString: @"http://www.apple.com/certificateauthority/AppleComputerRootCertificate.cer"]]; + SecCertificateRef cert = AppleRootCAFromKeychain(); + NSAssert(cert != NULL, @"Failed to load Apple Root CA from keychain"); + certificateData = CFBridgingRelease(SecCertificateCopyData(cert)); + CFRelease(cert); + } +#endif + + NSAssert(certificateData != nil, @"Certificate AppleRootCA is missed, add it to the bundle (ios) or provide access to keychain (osx) or specify url `setAppleRootCertificateURL`"); + + NSData *data = nil; + if (certificateData && [self verifyPCKS7:p7 withCertificateData:certificateData]) { struct pkcs7_st *contents = p7->d.sign->contents; if (PKCS7_type_is_data(contents)) @@ -305,7 +390,8 @@ + (NSData*)dataFromPCKS7Path:(NSString*)path } + (BOOL)verifyPCKS7:(PKCS7*)container withCertificateData:(NSData*)certificateData -{ // Based on: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW17 +{ + // Based on: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW17 static int verified = 1; int result = 0; OpenSSL_add_all_digests(); // Required for PKCS7_verify to work From 0235cd8757971a996f448681fe11e277c79a8be7 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 16:51:05 +0300 Subject: [PATCH 13/23] Changed dependency for subspec --- RMStore.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RMStore.podspec b/RMStore.podspec index 50379963..ef254218 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -33,7 +33,7 @@ Pod::Spec.new do |s| arv.dependency 'RMStore/Core' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' arv.dependency 'OpenSSL', '~> 1.0' - arv.frameworks = 'Security' + arv.osx.frameworks = 'Security' arv.resources = 'RMStore/Optional/AppleIncRootCertificate.cer' end From e7b0db7bca1e3073d2e4d804ee32937151744fe9 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 18:28:40 +0300 Subject: [PATCH 14/23] Fixe typo https://github.com/robotmedia/RMStore/issues/118 --- RMStore/Optional/RMAppReceipt.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 9de3a48a..5d76605a 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -376,7 +376,7 @@ + (NSData*)dataFromPCKS7Path:(NSString*)path NSAssert(certificateData != nil, @"Certificate AppleRootCA is missed, add it to the bundle (ios) or provide access to keychain (osx) or specify url `setAppleRootCertificateURL`"); NSData *data = nil; - if (certificateData && [self verifyPCKS7:p7 withCertificateData:certificateData]) + if (certificateData && [self verifyPKCS7:p7 withCertificateData:certificateData]) { struct pkcs7_st *contents = p7->d.sign->contents; if (PKCS7_type_is_data(contents)) @@ -389,7 +389,7 @@ + (NSData*)dataFromPCKS7Path:(NSString*)path return data; } -+ (BOOL)verifyPCKS7:(PKCS7*)container withCertificateData:(NSData*)certificateData ++ (BOOL)verifyPKCS7:(PKCS7*)container withCertificateData:(NSData*)certificateData { // Based on: https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html#//apple_ref/doc/uid/TP40010573-CH1-SW17 static int verified = 1; From f2ac0644befdb3ab9379542a1e458b609d68049b Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 18:34:52 +0300 Subject: [PATCH 15/23] Update read me. Update pod version. --- README.md | 5 +++-- RMStore.podspec | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 62fa551d..160906c7 100644 --- a/README.md +++ b/README.md @@ -274,11 +274,12 @@ RMStore requires iOS 5.0 or above and ARC. RMStore is in initial development and its public API should not be considered stable. Future enhancements will include: -* [Better OS X support](https://github.com/robotmedia/RMStore/issues/4) +* Tests for OS X +* Example app for OS X ##License - Copyright 2013-2014 [Robot Media SL](http://www.robotmedia.net) + Copyright 2013-2016 [Robot Media SL](http://www.robotmedia.net) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/RMStore.podspec b/RMStore.podspec index ef254218..cb27da67 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'RMStore' - s.version = '0.7.1' + s.version = '0.8.0' s.license = 'Apache 2.0' s.summary = 'A lightweight iOS library for In-App Purchases that adds blocks and notifications to StoreKit, plus verification, persistence and downloads.' s.homepage = 'https://github.com/robotmedia/RMStore' From a16f51a1de6a342a6d5966d9a2d6ddb4727150e6 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 19:21:02 +0300 Subject: [PATCH 16/23] Import io kit. --- RMStore/Optional/RMAppReceipt.m | 1 + 1 file changed, 1 insertion(+) diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 5d76605a..5a8f1511 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -27,6 +27,7 @@ #if TARGET_OS_IPHONE #import #elif TARGET_OS_MAC +#import #import #endif From e89e660bc1de9a045664e93d17154ba124dcd54b Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 19:49:15 +0300 Subject: [PATCH 17/23] Fixed target conditions. --- RMStore.podspec | 2 +- RMStore.xcodeproj/project.pbxproj | 8 ++++++-- RMStore/Optional/RMAppReceipt.m | 2 +- RMStoreDemo/RMAppDelegate.m | 4 +--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/RMStore.podspec b/RMStore.podspec index cb27da67..0acf291b 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -33,7 +33,7 @@ Pod::Spec.new do |s| arv.dependency 'RMStore/Core' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' arv.dependency 'OpenSSL', '~> 1.0' - arv.osx.frameworks = 'Security' + arv.osx.frameworks = 'Security', 'IOKit' arv.resources = 'RMStore/Optional/AppleIncRootCertificate.cer' end diff --git a/RMStore.xcodeproj/project.pbxproj b/RMStore.xcodeproj/project.pbxproj index 7d46e1f9..dc4995f2 100644 --- a/RMStore.xcodeproj/project.pbxproj +++ b/RMStore.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 52E207651D5CE26100E89C8F /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52E207641D5CE26100E89C8F /* IOKit.framework */; }; 52FE63A41D3531B00050814B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A31D3531B00050814B /* AppDelegate.m */; }; 52FE63A71D3531B00050814B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A61D3531B00050814B /* main.m */; }; 52FE63AA1D3531B00050814B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 52FE63A91D3531B00050814B /* ViewController.m */; }; @@ -97,6 +98,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 52E207641D5CE26100E89C8F /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; 52FE63A01D3531B00050814B /* RMStoreDemo_OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RMStoreDemo_OSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52FE63A21D3531B00050814B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 52FE63A31D3531B00050814B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; @@ -173,6 +175,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 52E207651D5CE26100E89C8F /* IOKit.framework in Frameworks */, 52FE63BB1D3534450050814B /* Security.framework in Frameworks */, 52FE63B91D3534390050814B /* StoreKit.framework in Frameworks */, 52FE63B41D35333F0050814B /* libcrypto.a in Frameworks */, @@ -327,6 +330,7 @@ A0AF3D0A17A802F300D2E836 /* Frameworks */ = { isa = PBXGroup; children = ( + 52E207641D5CE26100E89C8F /* IOKit.framework */, 52FE63BA1D3534450050814B /* Security.framework */, 52FE63B81D3534390050814B /* StoreKit.framework */, C90EF0F019A20C8200A9E738 /* XCTest.framework */, @@ -686,7 +690,7 @@ "$(inherited)", "$(PROJECT_DIR)/RMStore/Optional/openssl-1.0.1e/lib", ); - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.robotmedia.RMStoreDemo-OSX"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -727,7 +731,7 @@ "$(inherited)", "$(PROJECT_DIR)/RMStore/Optional/openssl-1.0.1e/lib", ); - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.7; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.robotmedia.RMStoreDemo-OSX"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 5a8f1511..269b7e4c 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -113,7 +113,7 @@ static int RMASN1ReadInteger(const uint8_t **pp, long omax) return RMASN1ReadString(pp, omax, V_ASN1_IA5STRING, NSASCIIStringEncoding); } -#if TARGET_OS_MAC +#if TARGET_OS_MAC && !TARGET_OS_IPHONE // Returns a CFData object, containing the computer's GUID. static CFDataRef CopyMACAddressData() diff --git a/RMStoreDemo/RMAppDelegate.m b/RMStoreDemo/RMAppDelegate.m index 34bc7e55..9bfe5938 100644 --- a/RMStoreDemo/RMAppDelegate.m +++ b/RMStoreDemo/RMAppDelegate.m @@ -22,7 +22,6 @@ #import "RMStoreViewController.h" #import "RMPurchasesViewController.h" #import "RMStore.h" -#import "RMStoreTransactionReceiptVerifier.h" #import "RMStoreAppReceiptVerifier.h" #import "RMStoreKeychainPersistence.h" @@ -51,8 +50,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( - (void)configureStore { - const BOOL iOS7OrHigher = floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1; - _receiptVerifier = iOS7OrHigher ? [[RMStoreAppReceiptVerifier alloc] init] : [[RMStoreTransactionReceiptVerifier alloc] init]; + _receiptVerifier = [[RMStoreAppReceiptVerifier alloc] init]; [RMStore defaultStore].receiptVerifier = _receiptVerifier; _persistence = [[RMStoreKeychainPersistence alloc] init]; From 4f9b2a2270a51a306e70b214f123f09f10ce2743 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Thu, 11 Aug 2016 20:25:20 +0300 Subject: [PATCH 18/23] Remove tests for the deprecated file. --- RMStore.xcodeproj/project.pbxproj | 4 -- .../RMStoreTransactionReceiptVerifierTests.m | 66 ------------------- 2 files changed, 70 deletions(-) delete mode 100644 RMStoreTests/RMStoreTransactionReceiptVerifierTests.m diff --git a/RMStore.xcodeproj/project.pbxproj b/RMStore.xcodeproj/project.pbxproj index dc4995f2..a6e17975 100644 --- a/RMStore.xcodeproj/project.pbxproj +++ b/RMStore.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ 8793E809180D512E005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; 8793E80B180D5133005D7A66 /* RMAppReceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E801180D512E005D7A66 /* RMAppReceipt.m */; }; 8793E80C180D5136005D7A66 /* RMStoreAppReceiptVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */; }; - 87950C2317E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 87950C2217E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m */; }; 87A2A3A0180D7B0400376773 /* RMAppReceiptTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 87A2A39F180D7B0400376773 /* RMAppReceiptTests.m */; }; 87A2A3A3180D817600376773 /* RMAppReceiptIAPTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 87A2A3A2180D817600376773 /* RMAppReceiptIAPTests.m */; }; 87A2A3A5180D82EF00376773 /* RMStoreAppReceiptVerifierTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 87A2A3A4180D82EF00376773 /* RMStoreAppReceiptVerifierTests.m */; }; @@ -130,7 +129,6 @@ 8793E801180D512E005D7A66 /* RMAppReceipt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAppReceipt.m; sourceTree = ""; }; 8793E802180D512E005D7A66 /* RMStoreAppReceiptVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMStoreAppReceiptVerifier.h; sourceTree = ""; }; 8793E803180D512E005D7A66 /* RMStoreAppReceiptVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMStoreAppReceiptVerifier.m; sourceTree = ""; }; - 87950C2217E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMStoreTransactionReceiptVerifierTests.m; sourceTree = ""; }; 87A2A39F180D7B0400376773 /* RMAppReceiptTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAppReceiptTests.m; sourceTree = ""; }; 87A2A3A1180D7E2900376773 /* RMStoreTests-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RMStoreTests-Prefix.pch"; sourceTree = ""; }; 87A2A3A2180D817600376773 /* RMAppReceiptIAPTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMAppReceiptIAPTests.m; sourceTree = ""; }; @@ -374,7 +372,6 @@ 87A2A3A4180D82EF00376773 /* RMStoreAppReceiptVerifierTests.m */, 8760464A18130CBB00C9B78C /* RMStoreKeychainPersistenceTests.m */, A0AF3D2917A802F300D2E836 /* RMStoreTests.m */, - 87950C2217E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m */, 87B7853E18105E6A00B5E54E /* RMStoreTransactionTests.m */, 87A2A3AB180E8AF500376773 /* RMStoreUserDefaultsPersistenceTests.m */, A0AF3D2317A802F300D2E836 /* Supporting Files */, @@ -600,7 +597,6 @@ 8700D1C117DCA548005C8F5D /* NSNotification+RMStoreTests.m in Sources */, 87B7853F18105E6A00B5E54E /* RMStoreTransactionTests.m in Sources */, 87D5A74217DE893E000E2B6C /* RMProducstRequestDelegateTests.m in Sources */, - 87950C2317E127A4001DF541 /* RMStoreTransactionReceiptVerifierTests.m in Sources */, 87A2A3A0180D7B0400376773 /* RMAppReceiptTests.m in Sources */, 87A2A3A3180D817600376773 /* RMAppReceiptIAPTests.m in Sources */, 87A2A3AC180E8AF500376773 /* RMStoreUserDefaultsPersistenceTests.m in Sources */, diff --git a/RMStoreTests/RMStoreTransactionReceiptVerifierTests.m b/RMStoreTests/RMStoreTransactionReceiptVerifierTests.m deleted file mode 100644 index 6c79da5e..00000000 --- a/RMStoreTests/RMStoreTransactionReceiptVerifierTests.m +++ /dev/null @@ -1,66 +0,0 @@ -// -// RMStoreTransactionReceiptVerifierTests.m -// RMStore -// -// Created by Hermes on 9/12/13. -// Copyright (c) 2013 Robot Media. All rights reserved. -// - -#import -#import "RMStoreTransactionReceiptVerifier.h" -#import - -@interface RMStoreTransactionReceiptVerifierTests : XCTestCase - -@end - -@implementation RMStoreTransactionReceiptVerifierTests { - RMStoreTransactionReceiptVerifier *_verifier; -} - -- (void)setUp -{ - _verifier = [[RMStoreTransactionReceiptVerifier alloc] init]; -} - -- (void)testVerifyTransaction_NoReceipt_Nil_Nil -{ - id transaction = [self mockPaymentTransactionWithReceipt:nil]; - [_verifier verifyTransaction:transaction success:nil failure:nil]; -} - -- (void)testVerifyTransaction_NoReceipt -{ - id transaction = [self mockPaymentTransactionWithReceipt:nil]; - [_verifier verifyTransaction:transaction success:^{ - XCTFail(@""); - } failure:^(NSError *error) { - XCTAssertNotNil(error, @""); - }]; -} - -- (void)testVerifyTransaction_Receipt -{ - NSData *receipt = [@"receipt" dataUsingEncoding:NSUTF8StringEncoding]; - id transaction = [self mockPaymentTransactionWithReceipt:receipt]; - [_verifier verifyTransaction:transaction success:^{ - XCTFail(@""); - } failure:^(NSError *error) { - }]; -} - -- (void)testVerifyTransaction_Receipt_Nil_Nil -{ - NSData *receipt = [@"receipt" dataUsingEncoding:NSUTF8StringEncoding]; - id transaction = [self mockPaymentTransactionWithReceipt:receipt]; - [_verifier verifyTransaction:transaction success:nil failure:nil]; -} - -- (id)mockPaymentTransactionWithReceipt:(NSData*)receipt -{ - id transaction = [OCMockObject mockForClass:[SKPaymentTransaction class]]; - [[[transaction stub] andReturn:receipt] transactionReceipt]; - return transaction; -} - -@end From 018106b51dcee78f7ba06606e31de153bb9c19e8 Mon Sep 17 00:00:00 2001 From: Sergey Popov Date: Fri, 9 Sep 2016 19:17:13 +0300 Subject: [PATCH 19/23] Changed open ssl dependency. --- RMStore.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RMStore.podspec b/RMStore.podspec index 0acf291b..bdefcff2 100644 --- a/RMStore.podspec +++ b/RMStore.podspec @@ -32,7 +32,7 @@ Pod::Spec.new do |s| s.subspec 'AppReceiptVerifier' do |arv| arv.dependency 'RMStore/Core' arv.source_files = 'RMStore/Optional/RMStoreAppReceiptVerifier.{h,m}', 'RMStore/Optional/RMAppReceipt.{h,m}' - arv.dependency 'OpenSSL', '~> 1.0' + arv.dependency 'OpenSSL-Universal', '~> 1.0' arv.osx.frameworks = 'Security', 'IOKit' arv.resources = 'RMStore/Optional/AppleIncRootCertificate.cer' end From 0481c79e04e0ba671baf65ae388ecaf6274ff9c7 Mon Sep 17 00:00:00 2001 From: Serj Date: Mon, 29 Oct 2018 16:49:18 +0300 Subject: [PATCH 20/23] Fix warnings --- RMStore/Optional/RMStoreAppReceiptVerifier.m | 8 ++--- RMStore/RMStore.h | 8 ++--- RMStore/RMStore.m | 34 +++++++++++++------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/RMStore/Optional/RMStoreAppReceiptVerifier.m b/RMStore/Optional/RMStoreAppReceiptVerifier.m index bcad2226..6757df88 100644 --- a/RMStore/Optional/RMStoreAppReceiptVerifier.m +++ b/RMStore/Optional/RMStoreAppReceiptVerifier.m @@ -24,8 +24,8 @@ @implementation RMStoreAppReceiptVerifier - (void)verifyTransaction:(SKPaymentTransaction*)transaction - success:(void (^)())successBlock - failure:(void (^)(NSError *error))failureBlock + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock { RMAppReceipt *receipt = [RMAppReceipt bundleReceipt]; const BOOL verified = [self verifyTransaction:transaction inReceipt:receipt success:successBlock failure:nil]; // failureBlock is nil intentionally. See below. @@ -87,8 +87,8 @@ - (BOOL)verifyAppReceipt:(RMAppReceipt*)receipt - (BOOL)verifyTransaction:(SKPaymentTransaction*)transaction inReceipt:(RMAppReceipt*)receipt - success:(void (^)())successBlock - failure:(void (^)(NSError *error))failureBlock + success:(void (^)(void))successBlock + failure:(void (^)(NSError *error))failureBlock { const BOOL receiptVerified = [self verifyAppReceipt:receipt]; if (!receiptVerified) diff --git a/RMStore/RMStore.h b/RMStore/RMStore.h index 7eb65f71..7ab0f4d9 100755 --- a/RMStore/RMStore.h +++ b/RMStore/RMStore.h @@ -132,7 +132,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; @param successBlock The block to be called if the refresh receipt request is sucessful. Can be `nil`. @param failureBlock The block to be called if the refresh receipt request fails. Can be `nil`. */ -- (void)refreshReceiptOnSuccess:(void (^)())successBlock +- (void)refreshReceiptOnSuccess:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; ///--------------------------------------------- @@ -197,7 +197,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; @discussion Hosted content from Apple’s server (@c SKDownload) is handled automatically by RMStore. */ - (void)downloadContentForTransaction:(SKPaymentTransaction*)transaction - success:(void (^)())successBlock + success:(void (^)(void))successBlock progress:(void (^)(float progress))progressBlock failure:(void (^)(NSError *error))failureBlock; @@ -217,7 +217,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; @param failureBlock Called if the transaction failed verification. If verification could not be completed (e.g., due to connection issues), then error must be of code RMStoreErrorCodeUnableToCompleteVerification to prevent RMStore to finish the transaction. Must be called in the main queu. */ - (void)verifyTransaction:(SKPaymentTransaction*)transaction - success:(void (^)())successBlock + success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; @end @@ -291,7 +291,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; /** Used in @c storeDownload*:. */ -@property (nonatomic, readonly) SKDownload *rm_storeDownload; +@property (nonatomic, readonly) SKDownload *rm_storeDownload NS_AVAILABLE(10_8, 6_0); /** Used in @c storeDownloadFailed:, @c storePaymentTransactionFailed:, @c storeProductsRequestFailed:, @c storeRefreshReceiptFailed: and @c storeRestoreTransactionsFailed:. */ diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index 1d57298a..c742ca17 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -61,13 +61,13 @@ typedef void (^RMSKProductsRequestFailureBlock)(NSError *error); typedef void (^RMSKProductsRequestSuccessBlock)(NSArray *products, NSArray *invalidIdentifiers); typedef void (^RMStoreFailureBlock)(NSError *error); -typedef void (^RMStoreSuccessBlock)(); +typedef void (^RMStoreSuccessBlock)(void); @implementation NSNotification(RMStore) - (float)rm_downloadProgress { - return [self.userInfo[RMStoreNotificationDownloadProgress] floatValue]; + return [[self.userInfo objectForKey:RMStoreNotificationDownloadProgress] floatValue]; } - (NSArray*)rm_invalidProductIdentifiers @@ -129,7 +129,8 @@ @interface RMStore() @end -@implementation RMStore { +@implementation RMStore +{ @private NSMutableDictionary *_addPaymentParameters; // HACK: We use a dictionary of product identifiers because the returned SKPayment is different from the one we add to the queue. Bad Apple. NSMutableDictionary *_products; @@ -142,7 +143,7 @@ @implementation RMStore { SKReceiptRefreshRequest *_refreshReceiptRequest; void (^_refreshReceiptFailureBlock)(NSError* error); - void (^_refreshReceiptSuccessBlock)(); + void (^_refreshReceiptSuccessBlock)(void); void (^_restoreTransactionsFailureBlock)(NSError* error); void (^_restoreTransactionsSuccessBlock)(NSArray* transactions); @@ -214,7 +215,10 @@ - (void)addPayment:(NSString*)productIdentifier SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product]; if ([payment respondsToSelector:@selector(setApplicationUsername:)]) { - payment.applicationUsername = userIdentifier; + if (@available(macOS 10.9, *)) + { + payment.applicationUsername = userIdentifier; + } } RMAddPaymentParameters *parameters = [[RMAddPaymentParameters alloc] init]; @@ -271,7 +275,10 @@ - (void)restoreTransactionsOfUser:(NSString*)userIdentifier _pendingRestoredTransactionsCount = 0; _restoreTransactionsSuccessBlock = successBlock; _restoreTransactionsFailureBlock = failureBlock; - [[SKPaymentQueue defaultQueue] restoreCompletedTransactionsWithApplicationUsername:userIdentifier]; + if (@available(macOS 10.9, *)) + { + [[SKPaymentQueue defaultQueue] restoreCompletedTransactionsWithApplicationUsername:userIdentifier]; + } } #pragma mark Receipt @@ -679,7 +686,7 @@ - (void)notifyRestoreTransactionFinishedIfApplicableAfterTransaction:(SKPaymentT - (RMAddPaymentParameters*)popAddPaymentParametersForIdentifier:(NSString*)identifier { - RMAddPaymentParameters *parameters = _addPaymentParameters[identifier]; + RMAddPaymentParameters *parameters = [_addPaymentParameters objectForKey:identifier]; [_addPaymentParameters removeObjectForKey:identifier]; return parameters; } @@ -719,22 +726,25 @@ - (void)request:(SKRequest *)request didFailWithError:(NSError *)error - (void)addProduct:(SKProduct*)product { - _products[product.productIdentifier] = product; + [_products setObject:product forKey:product.productIdentifier]; } -- (void)postNotificationWithName:(NSString*)notificationName download:(SKDownload*)download userInfoExtras:(NSDictionary*)extras +- (void)postNotificationWithName:(NSString*)notificationName download:(SKDownload *)download userInfoExtras:(NSDictionary*)extras API_AVAILABLE(macos(10.8)) { NSMutableDictionary *mutableExtras = extras ? [NSMutableDictionary dictionaryWithDictionary:extras] : [NSMutableDictionary dictionary]; mutableExtras[RMStoreNotificationStoreDownload] = download; - [self postNotificationWithName:notificationName transaction:download.transaction userInfoExtras:mutableExtras]; + if (@available(macOS 10.11, *)) + { + [self postNotificationWithName:notificationName transaction:download.transaction userInfoExtras:mutableExtras]; + } } - (void)postNotificationWithName:(NSString*)notificationName transaction:(SKPaymentTransaction*)transaction userInfoExtras:(NSDictionary*)extras { NSString *productIdentifier = transaction.payment.productIdentifier; NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; - userInfo[RMStoreNotificationTransaction] = transaction; - userInfo[RMStoreNotificationProductIdentifier] = productIdentifier; + [userInfo setObject:transaction forKey:RMStoreNotificationTransaction]; + [userInfo setObject:productIdentifier forKey:RMStoreNotificationProductIdentifier]; if (extras) { [userInfo addEntriesFromDictionary:extras]; From ee2faf20b6f9e939725c9fc6f16422c0622c1128 Mon Sep 17 00:00:00 2001 From: Serj Date: Mon, 29 Oct 2018 17:02:49 +0300 Subject: [PATCH 21/23] Remove warnings. --- RMStore/RMStore.m | 151 +++++++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 63 deletions(-) diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index c742ca17..c3f25a5f 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -72,36 +72,36 @@ - (float)rm_downloadProgress - (NSArray*)rm_invalidProductIdentifiers { - return (self.userInfo)[RMStoreNotificationInvalidProductIdentifiers]; + return [self.userInfo objectForKey:RMStoreNotificationInvalidProductIdentifiers]; } - (NSString*)rm_productIdentifier { - return (self.userInfo)[RMStoreNotificationProductIdentifier]; + return [self.userInfo objectForKey:RMStoreNotificationProductIdentifier]; } - (NSArray*)rm_products { - return (self.userInfo)[RMStoreNotificationProducts]; + return [self.userInfo objectForKey:RMStoreNotificationProducts]; } - (SKDownload*)rm_storeDownload { - return (self.userInfo)[RMStoreNotificationStoreDownload]; + return [self.userInfo objectForKey:RMStoreNotificationStoreDownload]; } - (NSError*)rm_storeError { - return (self.userInfo)[RMStoreNotificationStoreError]; + return [self.userInfo objectForKey:RMStoreNotificationStoreError]; } - (SKPaymentTransaction*)rm_transaction { - return (self.userInfo)[RMStoreNotificationTransaction]; + return [self.userInfo objectForKey:RMStoreNotificationTransaction]; } - (NSArray*)rm_transactions { - return (self.userInfo)[RMStoreNotificationTransactions]; + return [self.userInfo objectForKey:RMStoreNotificationTransactions]; } @end @@ -141,7 +141,7 @@ @implementation RMStore NSInteger _pendingRestoredTransactionsCount; BOOL _restoredCompletedTransactionsFinished; - SKReceiptRefreshRequest *_refreshReceiptRequest; + SKReceiptRefreshRequest *_refreshReceiptRequest NS_AVAILABLE(10_9, *); void (^_refreshReceiptFailureBlock)(NSError* error); void (^_refreshReceiptSuccessBlock)(void); @@ -224,7 +224,7 @@ - (void)addPayment:(NSString*)productIdentifier RMAddPaymentParameters *parameters = [[RMAddPaymentParameters alloc] init]; parameters.successBlock = successBlock; parameters.failureBlock = failureBlock; - _addPaymentParameters[productIdentifier] = parameters; + [_addPaymentParameters setObject:parameters forKey:productIdentifier]; [[SKPaymentQueue defaultQueue] addPayment:payment]; } @@ -300,7 +300,10 @@ - (void)refreshReceiptOnSuccess:(RMStoreSuccessBlock)successBlock { _refreshReceiptFailureBlock = failureBlock; _refreshReceiptSuccessBlock = successBlock; - _refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}]; + if (@available(macOS 10.9, *)) + { + _refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}]; + } _refreshReceiptRequest.delegate = self; [_refreshReceiptRequest start]; } @@ -309,7 +312,7 @@ - (void)refreshReceiptOnSuccess:(RMStoreSuccessBlock)successBlock - (SKProduct*)productForIdentifier:(NSString*)productIdentifier { - return _products[productIdentifier]; + return [_products objectForKey:productIdentifier]; } + (NSString*)localizedPriceOfProduct:(SKProduct*)product @@ -419,7 +422,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedW [[NSNotificationCenter defaultCenter] postNotificationName:RMSKRestoreTransactionsFailed object:self userInfo:userInfo]; } -- (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads +- (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads API_AVAILABLE(macos(10.8)) { for (SKDownload *download in downloads) { @@ -453,83 +456,102 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloa #pragma mark Download State -- (void)didCancelDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue +- (void)didCancelDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue API_AVAILABLE(macos(10.8)) { - SKPaymentTransaction *transaction = download.transaction; - RMStoreLog(@"download %@ for product %@ canceled", download.contentIdentifier, download.transaction.payment.productIdentifier); + if (@available(macOS 10.11, *)) + { + SKPaymentTransaction *transaction = download.transaction; + RMStoreLog(@"download %@ for product %@ canceled", download.contentIdentifier, download.transaction.payment.productIdentifier); - [self postNotificationWithName:RMSKDownloadCanceled download:download userInfoExtras:nil]; + [self postNotificationWithName:RMSKDownloadCanceled download:download userInfoExtras:nil]; - NSError *error = [NSError errorWithDomain:RMStoreErrorDomain code:RMStoreErrorCodeDownloadCanceled userInfo:@{NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Download canceled", @"RMStore", @"Error description")}]; + NSError *error = [NSError errorWithDomain:RMStoreErrorDomain code:RMStoreErrorCodeDownloadCanceled userInfo:@{NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Download canceled", @"RMStore", @"Error description")}]; - const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; - if (!hasPendingDownloads) - { - [self didFailTransaction:transaction queue:queue error:error]; + const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; + if (!hasPendingDownloads) + { + [self didFailTransaction:transaction queue:queue error:error]; + } } } -- (void)didFailDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue +- (void)didFailDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue API_AVAILABLE(macos(10.8)) { NSError *error = download.error; - SKPaymentTransaction *transaction = download.transaction; - RMStoreLog(@"download %@ for product %@ failed with error %@", download.contentIdentifier, transaction.payment.productIdentifier, error.debugDescription); + if (@available(macOS 10.11, *)) + { + SKPaymentTransaction *transaction = download.transaction; + RMStoreLog(@"download %@ for product %@ failed with error %@", download.contentIdentifier, transaction.payment.productIdentifier, error.debugDescription); - NSDictionary *extras = error ? @{RMStoreNotificationStoreError : error} : nil; - [self postNotificationWithName:RMSKDownloadFailed download:download userInfoExtras:extras]; + NSDictionary *extras = error ? @{RMStoreNotificationStoreError : error} : nil; + [self postNotificationWithName:RMSKDownloadFailed download:download userInfoExtras:extras]; - const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; - if (!hasPendingDownloads) - { - [self didFailTransaction:transaction queue:queue error:error]; + const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; + if (!hasPendingDownloads) + { + [self didFailTransaction:transaction queue:queue error:error]; + } } } -- (void)didFinishDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue +- (void)didFinishDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue API_AVAILABLE(macos(10.8)) { - SKPaymentTransaction *transaction = download.transaction; - RMStoreLog(@"download %@ for product %@ finished", download.contentIdentifier, transaction.payment.productIdentifier); - - [self postNotificationWithName:RMSKDownloadFinished download:download userInfoExtras:nil]; - - const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; - if (!hasPendingDownloads) + if (@available(macOS 10.11, *)) { - [self finishTransaction:download.transaction queue:queue]; + SKPaymentTransaction *transaction = download.transaction; + RMStoreLog(@"download %@ for product %@ finished", download.contentIdentifier, transaction.payment.productIdentifier); + + [self postNotificationWithName:RMSKDownloadFinished download:download userInfoExtras:nil]; + + const BOOL hasPendingDownloads = [self.class hasPendingDownloadsInTransaction:transaction]; + + if (!hasPendingDownloads) + { + [self finishTransaction:download.transaction queue:queue]; + } } } -- (void)didPauseDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue +- (void)didPauseDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue API_AVAILABLE(macos(10.8)) { - RMStoreLog(@"download %@ for product %@ paused", download.contentIdentifier, download.transaction.payment.productIdentifier); + if (@available(macOS 10.11, *)) + { + RMStoreLog(@"download %@ for product %@ paused", download.contentIdentifier, download.transaction.payment.productIdentifier); + } [self postNotificationWithName:RMSKDownloadPaused download:download userInfoExtras:nil]; } -- (void)didUpdateDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue +- (void)didUpdateDownload:(SKDownload*)download queue:(SKPaymentQueue*)queue API_AVAILABLE(macos(10.8)) { - RMStoreLog(@"download %@ for product %@ updated", download.contentIdentifier, download.transaction.payment.productIdentifier); + if (@available(macOS 10.11, *)) + { + RMStoreLog(@"download %@ for product %@ updated", download.contentIdentifier, download.transaction.payment.productIdentifier); + } NSDictionary *extras = @{RMStoreNotificationDownloadProgress : @(download.progress)}; [self postNotificationWithName:RMSKDownloadUpdated download:download userInfoExtras:extras]; } + (BOOL)hasPendingDownloadsInTransaction:(SKPaymentTransaction*)transaction { - for (SKDownload *download in transaction.downloads) + if (@available(macOS 10.8, *)) { + for (SKDownload *download in transaction.downloads) + { #if TARGET_OS_IPHONE - switch (download.downloadState) + switch (download.downloadState) #elif TARGET_OS_MAC - switch (download.state) + switch (download.state) #endif - { - case SKDownloadStateActive: - case SKDownloadStatePaused: - case SKDownloadStateWaiting: - return YES; - case SKDownloadStateCancelled: - case SKDownloadStateFailed: - case SKDownloadStateFinished: - continue; + { + case SKDownloadStateActive: + case SKDownloadStatePaused: + case SKDownloadStateWaiting: + return YES; + case SKDownloadStateCancelled: + case SKDownloadStateFailed: + case SKDownloadStateFinished: + continue; + } } } return NO; @@ -631,15 +653,18 @@ - (void)didVerifyTransaction:(SKPaymentTransaction *)transaction queue:(SKPaymen - (void)didDownloadSelfHostedContentForTransaction:(SKPaymentTransaction *)transaction queue:(SKPaymentQueue*)queue { - NSArray *downloads = [transaction respondsToSelector:@selector(downloads)] ? transaction.downloads : @[]; - if (downloads.count > 0) + if (@available(macOS 10.8, *)) { - RMStoreLog(@"starting downloads for product %@ started", transaction.payment.productIdentifier); - [queue startDownloads:downloads]; - } - else - { - [self finishTransaction:transaction queue:queue]; + NSArray *downloads = [transaction respondsToSelector:@selector(downloads)] ? transaction.downloads : @[]; + if (downloads.count > 0) + { + RMStoreLog(@"starting downloads for product %@ started", transaction.payment.productIdentifier); + [queue startDownloads:downloads]; + } + else + { + [self finishTransaction:transaction queue:queue]; + } } } From 18cfc8d6ddd6699aba25df8a2de56b0897742705 Mon Sep 17 00:00:00 2001 From: Serj Date: Mon, 29 Oct 2018 19:45:16 +0300 Subject: [PATCH 22/23] Fix warnings --- RMStore/Optional/RMAppReceipt.m | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/RMStore/Optional/RMAppReceipt.m b/RMStore/Optional/RMAppReceipt.m index 269b7e4c..fb831b38 100644 --- a/RMStore/Optional/RMAppReceipt.m +++ b/RMStore/Optional/RMAppReceipt.m @@ -237,17 +237,17 @@ - (instancetype)initWithASN1Data:(NSData*)asn1Data switch (type) { case RMAppReceiptASN1TypeBundleIdentifier: - _bundleIdentifierData = data; - _bundleIdentifier = RMASN1ReadUTF8String(&s, length); + self->_bundleIdentifierData = data; + self->_bundleIdentifier = RMASN1ReadUTF8String(&s, length); break; case RMAppReceiptASN1TypeAppVersion: - _appVersion = RMASN1ReadUTF8String(&s, length); + self->_appVersion = RMASN1ReadUTF8String(&s, length); break; case RMAppReceiptASN1TypeOpaqueValue: - _opaqueValue = data; + self->_opaqueValue = data; break; case RMAppReceiptASN1TypeHash: - _receiptHash = data; + self->_receiptHash = data; break; case RMAppReceiptASN1TypeInAppPurchaseReceipt: { @@ -256,12 +256,12 @@ - (instancetype)initWithASN1Data:(NSData*)asn1Data break; } case RMAppReceiptASN1TypeOriginalAppVersion: - _originalAppVersion = RMASN1ReadUTF8String(&s, length); + self->_originalAppVersion = RMASN1ReadUTF8String(&s, length); break; case RMAppReceiptASN1TypeExpirationDate: { NSString *string = RMASN1ReadIA5SString(&s, length); - _expirationDate = [RMAppReceipt formatRFC3339String:string]; + self->_expirationDate = [RMAppReceipt formatRFC3339String:string]; break; } } @@ -483,42 +483,42 @@ - (instancetype)initWithASN1Data:(NSData*)asn1Data switch (type) { case RMAppReceiptASN1TypeQuantity: - _quantity = RMASN1ReadInteger(&p, length); + self->_quantity = RMASN1ReadInteger(&p, length); break; case RMAppReceiptASN1TypeProductIdentifier: - _productIdentifier = RMASN1ReadUTF8String(&p, length); + self->_productIdentifier = RMASN1ReadUTF8String(&p, length); break; case RMAppReceiptASN1TypeTransactionIdentifier: - _transactionIdentifier = RMASN1ReadUTF8String(&p, length); + self->_transactionIdentifier = RMASN1ReadUTF8String(&p, length); break; case RMAppReceiptASN1TypePurchaseDate: { NSString *string = RMASN1ReadIA5SString(&p, length); - _purchaseDate = [RMAppReceipt formatRFC3339String:string]; + self->_purchaseDate = [RMAppReceipt formatRFC3339String:string]; break; } case RMAppReceiptASN1TypeOriginalTransactionIdentifier: - _originalTransactionIdentifier = RMASN1ReadUTF8String(&p, length); + self->_originalTransactionIdentifier = RMASN1ReadUTF8String(&p, length); break; case RMAppReceiptASN1TypeOriginalPurchaseDate: { NSString *string = RMASN1ReadIA5SString(&p, length); - _originalPurchaseDate = [RMAppReceipt formatRFC3339String:string]; + self->_originalPurchaseDate = [RMAppReceipt formatRFC3339String:string]; break; } case RMAppReceiptASN1TypeSubscriptionExpirationDate: { NSString *string = RMASN1ReadIA5SString(&p, length); - _subscriptionExpirationDate = [RMAppReceipt formatRFC3339String:string]; + self->_subscriptionExpirationDate = [RMAppReceipt formatRFC3339String:string]; break; } case RMAppReceiptASN1TypeWebOrderLineItemID: - _webOrderLineItemID = RMASN1ReadInteger(&p, length); + self->_webOrderLineItemID = RMASN1ReadInteger(&p, length); break; case RMAppReceiptASN1TypeCancellationDate: { NSString *string = RMASN1ReadIA5SString(&p, length); - _cancellationDate = [RMAppReceipt formatRFC3339String:string]; + self->_cancellationDate = [RMAppReceipt formatRFC3339String:string]; break; } } From 60cf084b9c78a52dbb810de033bf4f938be6c0fc Mon Sep 17 00:00:00 2001 From: Serj Date: Tue, 13 Nov 2018 19:38:37 +0300 Subject: [PATCH 23/23] Fix ns available --- RMStore/RMStore.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index c3f25a5f..e78050a4 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -141,7 +141,7 @@ @implementation RMStore NSInteger _pendingRestoredTransactionsCount; BOOL _restoredCompletedTransactionsFinished; - SKReceiptRefreshRequest *_refreshReceiptRequest NS_AVAILABLE(10_9, *); + SKReceiptRefreshRequest *_refreshReceiptRequest NS_AVAILABLE(10_9, 7_0); void (^_refreshReceiptFailureBlock)(NSError* error); void (^_refreshReceiptSuccessBlock)(void);