Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c536866906 | |||
| ede64d2e3b | |||
| 112a5a9e4f | |||
| 7d8cb7bd06 | |||
| da06a099ce | |||
| 95337f7544 | |||
| 7ee443a4af | |||
| ae082be181 | |||
| bcb0ee2c27 | |||
| f8dae53736 | |||
| 5c90e58864 | |||
| df47710990 | |||
| 9b03d4b850 | |||
| 06b43589d6 | |||
| 1722f04928 | |||
| 16ef7de4bf |
+2
-2
@@ -1,5 +1,5 @@
|
||||
language: objective-c
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode10
|
||||
|
||||
env:
|
||||
global:
|
||||
@@ -7,7 +7,7 @@ env:
|
||||
- LANG=en_US.UTF-8
|
||||
- PROJECT=AppReceiptValidator/AppReceiptValidator.xcodeproj
|
||||
matrix:
|
||||
- DESTINATION="OS=11.2,name=iPhone X" SCHEME="AppReceiptValidator Demo iOS"
|
||||
- DESTINATION="OS=12.0,name=iPhone X" SCHEME="AppReceiptValidator Demo iOS"
|
||||
- DESTINATION="arch=x86_64" SCHEME="AppReceiptValidator Demo macOS"
|
||||
|
||||
script:
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
sources:
|
||||
- AppReceiptValidator
|
||||
- Sourcery/Protocols
|
||||
templates:
|
||||
- Sourcery/Templates
|
||||
output:
|
||||
Sourcery/Generated
|
||||
@@ -4,7 +4,7 @@ disabled_rules:
|
||||
- nesting
|
||||
- todo
|
||||
excluded:
|
||||
- Sourcery/Generated
|
||||
- excluded_dir_example
|
||||
file_length:
|
||||
warning: 500
|
||||
large_tuple:
|
||||
|
||||
@@ -13,7 +13,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ class ViewController: UIViewController, UITextViewDelegate {
|
||||
self.inputTextView.delegate = self
|
||||
self.inputTextView.text = ""
|
||||
self.outputTextView.text = "Parsed Receipt will be shown here"
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(triggerAutoPaste), name: .UIApplicationWillEnterForeground, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(triggerAutoPaste), name: .UIPasteboardChanged, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(triggerAutoPaste), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(triggerAutoPaste), name: UIPasteboard.changedNotification, object: nil)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
||||
@@ -43,7 +43,7 @@ final class DropAcceptingTextView: NSTextView {
|
||||
fileprivate extension NSDraggingInfo {
|
||||
|
||||
var fileURLs: [URL] {
|
||||
let asStrings = self.draggingPasteboard().propertyList(forType: makeFileNameType()) as? [String] ?? []
|
||||
let asStrings = self.draggingPasteboard.propertyList(forType: makeFileNameType()) as? [String] ?? []
|
||||
return asStrings.map { URL(fileURLWithPath: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -22,7 +22,6 @@ class AppReceiptValidationInAppPurchaseTests: XCTestCase {
|
||||
} catch {
|
||||
XCTFail("Unexpectedly failed parsing a receipt \(error)")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testNonMindNodeReceiptParsingWithMultipleInAppPurchases() {
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
D1239FFF1F6A7B5000D0421E /* AppleIncRootCertificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = D19095C41F601DEA0095729B /* AppleIncRootCertificate.cer */; };
|
||||
D123A0001F6A7CCF00D0421E /* AppleIncRootCertificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = D19095C41F601DEA0095729B /* AppleIncRootCertificate.cer */; };
|
||||
D13E5B7D20331B9B001880F0 /* DropAcceptingTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13E5B7C20331B9B001880F0 /* DropAcceptingTextView.swift */; };
|
||||
D14FA7261F61350F00545540 /* AutoEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14FA71F1F6134CF00545540 /* AutoEquatable.swift */; };
|
||||
D14FA7271F61351000545540 /* AutoEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14FA71F1F6134CF00545540 /* AutoEquatable.swift */; };
|
||||
D14FA7291F61351400545540 /* AutoEquatable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14FA71E1F6134CF00545540 /* AutoEquatable.generated.swift */; };
|
||||
D14FA72A1F61351500545540 /* AutoEquatable.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14FA71E1F6134CF00545540 /* AutoEquatable.generated.swift */; };
|
||||
D14FA7321F61476700545540 /* mac_mindnode_rebought_receipt in Resources */ = {isa = PBXBuildFile; fileRef = D14FA7311F61472400545540 /* mac_mindnode_rebought_receipt */; };
|
||||
D14FA7331F61476800545540 /* mac_mindnode_rebought_receipt in Resources */ = {isa = PBXBuildFile; fileRef = D14FA7311F61472400545540 /* mac_mindnode_rebought_receipt */; };
|
||||
D14FA7381F6181C700545540 /* OpenSSLWrappers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D14FA7371F6181C700545540 /* OpenSSLWrappers.swift */; };
|
||||
@@ -280,9 +276,6 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D13E5B7C20331B9B001880F0 /* DropAcceptingTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropAcceptingTextView.swift; sourceTree = "<group>"; };
|
||||
D14FA71E1F6134CF00545540 /* AutoEquatable.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoEquatable.generated.swift; sourceTree = "<group>"; };
|
||||
D14FA71F1F6134CF00545540 /* AutoEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoEquatable.swift; sourceTree = "<group>"; };
|
||||
D14FA7221F6134CF00545540 /* AutoEquatable.stencil */ = {isa = PBXFileReference; lastKnownFileType = text; path = AutoEquatable.stencil; sourceTree = "<group>"; };
|
||||
D14FA72E1F6143C400545540 /* Date+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Convenience.swift"; sourceTree = "<group>"; };
|
||||
D14FA7311F61472400545540 /* mac_mindnode_rebought_receipt */ = {isa = PBXFileReference; lastKnownFileType = file; path = mac_mindnode_rebought_receipt; sourceTree = "<group>"; };
|
||||
D14FA7371F6181C700545540 /* OpenSSLWrappers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSLWrappers.swift; sourceTree = "<group>"; };
|
||||
@@ -542,40 +535,6 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D14FA71B1F6134CF00545540 /* Sourcery */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D14FA7231F6134EC00545540 /* Protocols */,
|
||||
D14FA71D1F6134CF00545540 /* Generated */,
|
||||
D14FA7201F6134CF00545540 /* Templates */,
|
||||
);
|
||||
path = Sourcery;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D14FA71D1F6134CF00545540 /* Generated */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D14FA71E1F6134CF00545540 /* AutoEquatable.generated.swift */,
|
||||
);
|
||||
path = Generated;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D14FA7201F6134CF00545540 /* Templates */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D14FA7221F6134CF00545540 /* AutoEquatable.stencil */,
|
||||
);
|
||||
path = Templates;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D14FA7231F6134EC00545540 /* Protocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D14FA71F1F6134CF00545540 /* AutoEquatable.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D14FA7341F614A9C00545540 /* OpenSSL */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -851,7 +810,6 @@
|
||||
D1D6F4921F5D67E600E86FE1 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D14FA71B1F6134CF00545540 /* Sourcery */,
|
||||
D1D6F4FC1F5D696800E86FE1 /* AppReceiptValidator */,
|
||||
D1D6F4E51F5D691400E86FE1 /* AppReceiptValidator Demo iOS */,
|
||||
D19095821F6000A40095729B /* AppReceiptValidator Demo macOS */,
|
||||
@@ -1135,6 +1093,7 @@
|
||||
D190957D1F6000A40095729B /* Sources */,
|
||||
D190957E1F6000A40095729B /* Frameworks */,
|
||||
D190957F1F6000A40095729B /* Resources */,
|
||||
D1DEE48D20EBAEE800F95036 /* Swiftlint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1190,7 +1149,6 @@
|
||||
D1D6F4B11F5D684C00E86FE1 /* Frameworks */,
|
||||
D1D6F4B21F5D684C00E86FE1 /* Headers */,
|
||||
D1D6F4B31F5D684C00E86FE1 /* Resources */,
|
||||
D1D6F52D1F5D872200E86FE1 /* Swiftlint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1209,7 +1167,6 @@
|
||||
D1D6F4BE1F5D687400E86FE1 /* Frameworks */,
|
||||
D1D6F4BF1F5D687400E86FE1 /* Headers */,
|
||||
D1D6F4C01F5D687400E86FE1 /* Resources */,
|
||||
D1D6F52E1F5D872B00E86FE1 /* Swiftlint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1228,6 +1185,7 @@
|
||||
D1D6F4E11F5D691400E86FE1 /* Frameworks */,
|
||||
D1D6F4E21F5D691400E86FE1 /* Resources */,
|
||||
D1D6F5071F5D696800E86FE1 /* Embed Frameworks */,
|
||||
D1DEE48C20EBAEC800F95036 /* Swiftlint */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1251,6 +1209,7 @@
|
||||
TargetAttributes = {
|
||||
D19095801F6000A40095729B = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
@@ -1260,27 +1219,27 @@
|
||||
};
|
||||
D19095911F6000A40095729B = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = D19095801F6000A40095729B;
|
||||
};
|
||||
D19095A81F6001800095729B = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
TestTargetID = D1D6F4E31F5D691400E86FE1;
|
||||
};
|
||||
D1D6F4B41F5D684C00E86FE1 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
D1D6F4C11F5D687400E86FE1 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
D1D6F4E31F5D691400E86FE1 = {
|
||||
CreatedOnToolsVersion = 9.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
@@ -1381,33 +1340,43 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
D1D6F52D1F5D872200E86FE1 /* Swiftlint */ = {
|
||||
D1DEE48C20EBAEC800F95036 /* Swiftlint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)",
|
||||
);
|
||||
name = Swiftlint;
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
D1D6F52E1F5D872B00E86FE1 /* Swiftlint */ = {
|
||||
D1DEE48D20EBAEE800F95036 /* Swiftlint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(SRCROOT)",
|
||||
);
|
||||
name = Swiftlint;
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@@ -1454,8 +1423,6 @@
|
||||
D1D6F53F1F5D89D000E86FE1 /* AppReceiptValidator.swift in Sources */,
|
||||
D1FE34401F604F540029576B /* AppReceiptValidator+Parameters.swift in Sources */,
|
||||
D19095C31F6019FC0095729B /* DeviceIdentifier+installedDeviceIdentifier_iOS.swift in Sources */,
|
||||
D14FA7271F61351000545540 /* AutoEquatable.swift in Sources */,
|
||||
D14FA7291F61351400545540 /* AutoEquatable.generated.swift in Sources */,
|
||||
D1DFC5DA20037B8400C7B99B /* KnownOrUnknown.swift in Sources */,
|
||||
D1FE343D1F604F020029576B /* Receipt.swift in Sources */,
|
||||
D14FA73B1F618B0100545540 /* ASN1Helpers.swift in Sources */,
|
||||
@@ -1473,11 +1440,9 @@
|
||||
D1FE34411F604F540029576B /* AppReceiptValidator+Parameters.swift in Sources */,
|
||||
D19095C01F60158B0095729B /* DeviceIdentifier+installedDeviceIdentifier_macOS.swift in Sources */,
|
||||
D1FE343E1F604F020029576B /* Receipt.swift in Sources */,
|
||||
D14FA72A1F61351500545540 /* AutoEquatable.generated.swift in Sources */,
|
||||
D1DFC5DB20037B8400C7B99B /* KnownOrUnknown.swift in Sources */,
|
||||
D14FA73C1F618B0100545540 /* ASN1Helpers.swift in Sources */,
|
||||
D14FA7391F6181D000545540 /* OpenSSLWrappers.swift in Sources */,
|
||||
D14FA7261F61350F00545540 /* AutoEquatable.swift in Sources */,
|
||||
D19095BD1F6004D10095729B /* pkcs7_union_accessors.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -1558,7 +1523,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1576,7 +1541,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1584,7 +1549,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@@ -1595,8 +1559,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator-Demo-macOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AppReceiptValidator Demo macOS.app/Contents/MacOS/AppReceiptValidator Demo macOS";
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1604,7 +1567,6 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
@@ -1615,8 +1577,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator-Demo-macOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 4.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AppReceiptValidator Demo macOS.app/Contents/MacOS/AppReceiptValidator Demo macOS";
|
||||
SWIFT_VERSION = 4.2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1629,9 +1590,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AppReceiptValidator Demo iOS.app/AppReceiptValidator Demo iOS";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -1644,9 +1604,8 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator-iOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AppReceiptValidator Demo iOS.app/AppReceiptValidator Demo iOS";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -1789,6 +1748,7 @@
|
||||
PRODUCT_NAME = AppReceiptValidator;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -1818,6 +1778,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ideasoncanvas.AppReceiptValidator;
|
||||
PRODUCT_NAME = AppReceiptValidator;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -1849,6 +1810,7 @@
|
||||
PRODUCT_NAME = AppReceiptValidator;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@@ -1879,6 +1841,7 @@
|
||||
PRODUCT_NAME = AppReceiptValidator;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.2;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@@ -1896,7 +1859,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator.Demo-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -1912,7 +1875,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.ideasoncanvas.AppReceiptValidator.Demo-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
+3
-1
@@ -43,7 +43,9 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D19095A81F6001800095729B"
|
||||
|
||||
+3
-1
@@ -43,7 +43,9 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D19095911F6000A40095729B"
|
||||
|
||||
+21
@@ -28,7 +28,28 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D19095A81F6001800095729B"
|
||||
BuildableName = "AppReceiptValidator Tests iOS.xctest"
|
||||
BlueprintName = "AppReceiptValidator Tests iOS"
|
||||
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D1D6F4B41F5D684C00E86FE1"
|
||||
BuildableName = "AppReceiptValidator.framework"
|
||||
BlueprintName = "AppReceiptValidator iOS"
|
||||
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
|
||||
+6
-18
@@ -20,20 +20,6 @@
|
||||
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D1D6F5321F5D894900E86FE1"
|
||||
BuildableName = "AppReceiptValidator_macOSTests.xctest"
|
||||
BlueprintName = "AppReceiptValidator_macOSTests"
|
||||
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
@@ -43,12 +29,14 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
skipped = "NO"
|
||||
parallelizable = "YES"
|
||||
testExecutionOrdering = "random">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D1D6F5321F5D894900E86FE1"
|
||||
BuildableName = "AppReceiptValidator_macOSTests.xctest"
|
||||
BlueprintName = "AppReceiptValidator_macOSTests"
|
||||
BlueprintIdentifier = "D19095911F6000A40095729B"
|
||||
BuildableName = "AppReceiptValidator Tests macOS.xctest"
|
||||
BlueprintName = "AppReceiptValidator Tests macOS"
|
||||
ReferencedContainer = "container:AppReceiptValidator.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
|
||||
@@ -336,7 +336,6 @@ private extension AppReceiptValidator {
|
||||
case expirationDate = 21
|
||||
}
|
||||
|
||||
|
||||
/// See Receipt.swift for details and a link to Apple reference
|
||||
enum KnownInAppPurchaseAttribute: Int32 {
|
||||
case quantity = 1701
|
||||
|
||||
@@ -11,7 +11,7 @@ import Foundation
|
||||
/// Receipts are made up of a number of fields. This represents all fields that are available locally when parsing a receipt file in ASN.1 form.
|
||||
///
|
||||
/// See [Apple Reference](https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html)
|
||||
public struct Receipt {
|
||||
public struct Receipt: Equatable {
|
||||
|
||||
/// The app’s bundle identifier. This corresponds to the value of `CFBundleIdentifier` in the Info.plist file.
|
||||
/// Use this value to validate if the receipt was indeed generated for your app. ASN.1 Field Type 2.
|
||||
@@ -70,10 +70,6 @@ public struct Receipt {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
|
||||
extension Receipt: AutoEquatable {}
|
||||
|
||||
// MARK: - CustomStringConvertible
|
||||
|
||||
extension Receipt: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
@@ -115,7 +111,7 @@ extension Receipt: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
/// - Subscription Auto Renew Status
|
||||
/// - Subscription Auto Renew Preference
|
||||
/// - Subscription Price Consent Status
|
||||
public struct InAppPurchaseReceipt {
|
||||
public struct InAppPurchaseReceipt: Equatable {
|
||||
|
||||
/// The number of items purchased. ASN.1 Field Type 1701.
|
||||
/// This value corresponds to the quantity property of the `SKPayment` object stored in the transaction’s payment property.
|
||||
@@ -189,10 +185,6 @@ public struct InAppPurchaseReceipt {
|
||||
public init() {}
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
|
||||
extension InAppPurchaseReceipt: AutoEquatable {}
|
||||
|
||||
// MARK: - CustomStringConvertible
|
||||
|
||||
extension InAppPurchaseReceipt: CustomStringConvertible, CustomDebugStringConvertible {
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Generated using Sourcery 0.10.0 — https://github.com/krzysztofzablocki/Sourcery
|
||||
// DO NOT EDIT
|
||||
|
||||
// swiftlint:disable file_length
|
||||
private func compareOptionals<T>(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (lValue?, rValue?):
|
||||
return compare(lValue, rValue)
|
||||
case (nil, nil):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private func compareArrays<T>(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool {
|
||||
guard lhs.count == rhs.count else { return false }
|
||||
for (idx, lhsItem) in lhs.enumerated() {
|
||||
guard compare(lhsItem, rhs[idx]) else { return false }
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// MARK: - AutoEquatable for classes, protocols, structs
|
||||
// MARK: - InAppPurchaseReceipt AutoEquatable
|
||||
extension InAppPurchaseReceipt: Equatable {}
|
||||
public func == (lhs: InAppPurchaseReceipt, rhs: InAppPurchaseReceipt) -> Bool {
|
||||
guard compareOptionals(lhs: lhs.quantity, rhs: rhs.quantity, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.productIdentifier, rhs: rhs.productIdentifier, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.transactionIdentifier, rhs: rhs.transactionIdentifier, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.originalTransactionIdentifier, rhs: rhs.originalTransactionIdentifier, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.purchaseDate, rhs: rhs.purchaseDate, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.originalPurchaseDate, rhs: rhs.originalPurchaseDate, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.subscriptionExpirationDate, rhs: rhs.subscriptionExpirationDate, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.cancellationDate, rhs: rhs.cancellationDate, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.webOrderLineItemId, rhs: rhs.webOrderLineItemId, compare: ==) else { return false }
|
||||
return true
|
||||
}
|
||||
// MARK: - Receipt AutoEquatable
|
||||
extension Receipt: Equatable {}
|
||||
public func == (lhs: Receipt, rhs: Receipt) -> Bool {
|
||||
guard compareOptionals(lhs: lhs.bundleIdentifier, rhs: rhs.bundleIdentifier, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.bundleIdData, rhs: rhs.bundleIdData, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.appVersion, rhs: rhs.appVersion, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.opaqueValue, rhs: rhs.opaqueValue, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.sha1Hash, rhs: rhs.sha1Hash, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.originalAppVersion, rhs: rhs.originalAppVersion, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.receiptCreationDate, rhs: rhs.receiptCreationDate, compare: ==) else { return false }
|
||||
guard compareOptionals(lhs: lhs.expirationDate, rhs: rhs.expirationDate, compare: ==) else { return false }
|
||||
guard lhs.inAppPurchaseReceipts == rhs.inAppPurchaseReceipts else { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - AutoEquatable for Enums
|
||||
@@ -1,8 +0,0 @@
|
||||
//
|
||||
// AutoEquatable.swift
|
||||
//
|
||||
//
|
||||
// Created by Hannes Oud on 07.09.17.
|
||||
//
|
||||
|
||||
protocol AutoEquatable {}
|
||||
@@ -1,62 +0,0 @@
|
||||
// swiftlint:disable file_length
|
||||
fileprivate func compareOptionals<T>(lhs: T?, rhs: T?, compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (lValue?, rValue?):
|
||||
return compare(lValue, rValue)
|
||||
case (nil, nil):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func compareArrays<T>(lhs: [T], rhs: [T], compare: (_ lhs: T, _ rhs: T) -> Bool) -> Bool {
|
||||
guard lhs.count == rhs.count else { return false }
|
||||
for (idx, lhsItem) in lhs.enumerated() {
|
||||
guard compare(lhsItem, rhs[idx]) else { return false }
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
{% macro compareVariables variables %}
|
||||
{% for variable in variables where variable.readAccess != "private" and variable.readAccess != "fileprivate" %}{% if not variable.annotations.skipEquality %}guard {% if not variable.isOptional %}{% if not variable.annotations.arrayEquality %}lhs.{{ variable.name }} == rhs.{{ variable.name }}{% else %}compareArrays(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %}{% else %}compareOptionals(lhs: lhs.{{ variable.name }}, rhs: rhs.{{ variable.name }}, compare: ==){% endif %} else { return false }{% endif %}
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
|
||||
// MARK: - AutoEquatable for classes, protocols, structs
|
||||
{% for type in types.implementing.AutoEquatable|!enum %}
|
||||
// MARK: - {{ type.name }} AutoEquatable
|
||||
{% if not type.kind == "protocol" %}extension {{ type.name }}: Equatable {}{% endif %}
|
||||
{% if type.supertype.based.Equatable or type.supertype.implements.AutoEquatable %}THIS WONT COMPILE, WE DONT SUPPORT INHERITANCE for AutoEquatable{% endif %}
|
||||
{{ type.accessLevel }} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
|
||||
{% if not type.kind == "protocol" %}
|
||||
{% call compareVariables type.storedVariables %}
|
||||
{% else %}
|
||||
{% call compareVariables type.allVariables %}
|
||||
{% endif %}
|
||||
return true
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
// MARK: - AutoEquatable for Enums
|
||||
{% for type in types.implementing.AutoEquatable|enum %}
|
||||
// MARK: - {{ type.name }} AutoEquatable
|
||||
extension {{ type.name }}: Equatable {}
|
||||
{{ type.accessLevel }} func == (lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
{% for case in type.cases %}
|
||||
{% if case.hasAssociatedValue %}case (.{{ case.name }}(let lhs), .{{ case.name }}(let rhs)):{% else %}case (.{{ case.name }}, .{{ case.name }}):{% endif %}
|
||||
{% ifnot case.hasAssociatedValue %}return true{% else %}
|
||||
{% if case.associatedValues.count == 1 %}
|
||||
return lhs == rhs
|
||||
{% else %}
|
||||
{% for associated in case.associatedValues %}if lhs.{{ associated.externalName }} != rhs.{{ associated.externalName }} { return false }
|
||||
{% endfor %}return true
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if type.cases.count > 1 %}default: return false{% endif %}
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://github.com/Carthage/Carthage)
|
||||

|
||||

|
||||

|
||||
[](LICENSE)
|
||||
[](https://travis-ci.org/IdeasOnCanvas/AppReceiptValidator)
|
||||
[](https://twitter.com/hannesoid)
|
||||
@@ -73,7 +73,7 @@ Receipt(
|
||||
)
|
||||
```
|
||||
|
||||
**Receipt** is *Equatable*, thanks [Sourcery](https://github.com/krzysztofzablocki/Sourcery), so you can do comparisons in Unit Tests.
|
||||
**Receipt** is *Equatable*, so you can do comparisons in Unit Tests.
|
||||
There are also some opt-in unofficial attributes, but this is experimental and should not be used in production.
|
||||
|
||||
### Validating a receipt's signature and hash
|
||||
@@ -150,19 +150,20 @@ If you have no receipt (happens in development builds) or your receipt is invali
|
||||
|
||||
### AppReceiptValidator Uses OpenSSL
|
||||
|
||||
OpenSSL is used for pkcs7 container parsing and signature validation, and also for parsing the ASN1 payload of the pkcs7, which contains the receipts attributes.
|
||||
OpenSSL is used for PKCS#7 container parsing and signature validation, and also for parsing the ASN1 payload of the PKCS#7, which contains the receipts attributes.
|
||||
|
||||
### Other Options
|
||||
|
||||
##### Alternatives to PKCS7 of OpenSSL
|
||||
##### Alternatives to PKCS#7 of OpenSSL
|
||||
|
||||
- `Security.framework` - `CMSDecoder` for PKCS7 interaction *only available on macOS*
|
||||
- `BoringSSL` instead of OpenSSL, Pod, *only available on iOS (?)*
|
||||
- `Security.framework` - `CMSDecoder` for PKCS#7 interaction *only available on macOS*, [AppStoreReceiptChecker](https://github.com/delicious-monster/AppStoreReceiptChecker) uses this.
|
||||
- `BoringSSL` instead of OpenSSL, seems included as frameworks in modern iOS and macOS, but not officially supported?
|
||||
|
||||
##### Alternatives to ASN1 of OpenSSL
|
||||
|
||||
- [decoding-asn1-der-sequences-in-swift](http://nspasteboard.com/2016/10/23/decoding-asn1-der-sequences-in-swift/) implemented [here](https://gist.github.com/Jugale/2daaec0715d4f6d7347534d42bfa7110)
|
||||
- [Asn1Parser.swift](https://github.com/TakeScoop/SwiftyRSA/blob/03250be7319d8c54159234e5258ead395ea4de4c/SwiftyRSA/Asn1Parser.swift)
|
||||
- [AppStoreReceiptChecker](https://github.com/delicious-monster/AppStoreReceiptChecker)
|
||||
|
||||
##### Validation Server to Server
|
||||
An app can send its receipt file to a backend from where Apples receipt API can be called. See Resources.
|
||||
@@ -187,6 +188,7 @@ Advantages doing it locally:
|
||||
- [nsomar about Module Maps 1](http://nsomar.com/project-and-private-headers-in-a-swift-and-objective-c-framework/)
|
||||
- [nsomar about Module Maps 2](http://nsomar.com/modular-framework-creating-and-using-them/)
|
||||
- [SwiftyStoreKit](https://github.com/bizz84/SwiftyStoreKit)
|
||||
- [AppStoreReceiptChecker](https://github.com/delicious-monster/AppStoreReceiptChecker) - macOS, uses CMSDecoder and a Swift ASN1 Implementation
|
||||
|
||||
## Updating Apple Root Certificate
|
||||
For convenience, AppReceiptValidator contains a copy of apples root certificate to validate the signature against. If uncomfortable with this, you can specify your own by changing the parameters like this:
|
||||
|
||||
Reference in New Issue
Block a user