Compare commits

...

17 Commits

Author SHA1 Message Date
Hannes Oud 1ba0b31095 Merge pull request #51 from IdeasOnCanvas/enhancement/deviceIdentifierFromMacAddress
Support DeviceIdentifier from MAC Address String
2018-11-22 16:11:06 +01:00
Hannes Oud 5121e901f5 Remove unneeded prefix 2018-11-22 16:10:44 +01:00
Hannes Oud d31ab05fe2 Update gif 2018-11-22 12:29:06 +01:00
Hannes Oud c4769bc42a Update mac demo app to support identifiers 2018-11-22 12:22:58 +01:00
Hannes Oud 6605544598 Add tests for DeviceIdentifier 2018-11-22 11:54:19 +01:00
Hannes Oud 3bb92db368 Add DeviceIdentifier initializer with macAddress string 2018-11-22 11:48:28 +01:00
Hannes Oud 97b0adff0a Make primary mac address function internal (testable) 2018-11-22 11:48:13 +01:00
Hannes Oud bf875864ea Fix typo 2018-11-22 11:47:50 +01:00
Hannes Oud c536866906 Merge pull request #50 from IdeasOnCanvas/chore/Xcode10
Update to Xcode 10 and Swift 4.2
2018-09-24 17:20:23 +02:00
Hannes Oud ede64d2e3b Update Swift version in Readme 2018-09-24 16:10:10 +02:00
Hannes Oud 112a5a9e4f Update travis.yml for Xcode 10 and iOS 12 2018-09-24 16:09:19 +02:00
Hannes Oud 7d8cb7bd06 Update schemes, parrallelize tests and make execution order random 2018-09-24 16:06:41 +02:00
Hannes Oud da06a099ce Make tests unhosted 2018-09-24 16:04:18 +02:00
Hannes Oud 95337f7544 Upgrade to Swift 4.2 and Xcode 10 2018-09-24 16:00:56 +02:00
Hannes Oud 7ee443a4af Merge pull request #49 from IdeasOnCanvas/chore/core/moveSwiftlintFromFrameworkTarget
Move Swiftlint run script phases to example project
2018-07-05 11:03:21 +02:00
Hannes Oud ae082be181 Remove placeholder comment from script phase 2018-07-05 11:01:48 +02:00
Hannes Oud bcb0ee2c27 Move Swiftlint run script phases to example project 2018-07-03 15:23:48 +02:00
16 changed files with 226 additions and 81 deletions
+2 -2
View File
@@ -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:
@@ -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) {
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@@ -686,7 +685,7 @@
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="AppReceiptValidator Receipt Parser" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
<window key="window" title="AppReceiptValidator Receipt Parser" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
@@ -712,78 +711,93 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ynK-dw-fFc">
<rect key="frame" x="0.0" y="0.0" width="316" height="270"/>
<clipView key="contentView" id="yEL-yO-YvB">
<rect key="frame" x="1" y="1" width="314" height="268"/>
<rect key="frame" x="0.0" y="22" width="316" height="248"/>
<clipView key="contentView" drawsBackground="NO" id="yEL-yO-YvB">
<rect key="frame" x="1" y="1" width="314" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView toolTip="Paste Base64 here" importsGraphics="NO" richText="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" usesRuler="YES" allowsNonContiguousLayout="YES" textCompletion="NO" id="0xW-mT-lME" customClass="DropAcceptingTextView" customModule="AppReceiptValidator_Demo_macOS" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="314" height="268"/>
<rect key="frame" x="0.0" y="0.0" width="314" height="246"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="314" height="268"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="314" height="246"/>
<size key="maxSize" width="629" height="10000000"/>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="TaD-v9-pOg">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="TaD-v9-pOg">
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="hkR-e4-WtN">
<rect key="frame" x="299" y="1" width="16" height="268"/>
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="hkR-e4-WtN">
<rect key="frame" x="299" y="1" width="16" height="246"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<scrollView toolTip="Parsed Receipt will be shown here" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6mt-ay-mAL">
<rect key="frame" x="316" y="0.0" width="315" height="270"/>
<clipView key="contentView" id="YwZ-F9-Cvh">
<clipView key="contentView" drawsBackground="NO" id="YwZ-F9-Cvh">
<rect key="frame" x="1" y="1" width="313" height="268"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView importsGraphics="NO" richText="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" usesRuler="YES" allowsNonContiguousLayout="YES" textCompletion="NO" id="GHT-gS-G1g" customClass="TextView" customModule="AppReceiptValidator_Demo_macOS" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="313" height="268"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="313" height="268"/>
<size key="maxSize" width="463" height="10000000"/>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="xmd-vm-w1P">
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="xmd-vm-w1P">
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="uk9-Sg-RUp">
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="uk9-Sg-RUp">
<rect key="frame" x="298" y="1" width="16" height="268"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="yvX-By-nNw">
<rect key="frame" x="0.0" y="0.0" width="316" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Optional DeviceIdentifier for Validation (MAC Address, UUID, Base64)" drawsBackground="YES" id="Z2r-sB-vIS">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<action selector="identifierDidChange:" target="XfG-lQ-9wD" id="ccM-mH-NPQ"/>
</connections>
</textField>
</subviews>
<constraints>
<constraint firstItem="6mt-ay-mAL" firstAttribute="leading" secondItem="yvX-By-nNw" secondAttribute="trailing" id="231-cE-39Q"/>
<constraint firstItem="6mt-ay-mAL" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="CdY-lv-wee"/>
<constraint firstItem="ynK-dw-fFc" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="Cvz-FD-lzg"/>
<constraint firstItem="yvX-By-nNw" firstAttribute="top" secondItem="ynK-dw-fFc" secondAttribute="bottom" id="KSy-yc-TCD"/>
<constraint firstItem="ynK-dw-fFc" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="Rno-M6-Pjq"/>
<constraint firstItem="6mt-ay-mAL" firstAttribute="width" secondItem="m2S-Jp-Qdl" secondAttribute="width" multiplier="1:2" id="SWu-Yn-pVc"/>
<constraint firstAttribute="bottom" secondItem="yvX-By-nNw" secondAttribute="bottom" id="WOQ-2e-jWj"/>
<constraint firstAttribute="trailing" secondItem="6mt-ay-mAL" secondAttribute="trailing" id="Yun-Rd-wsm"/>
<constraint firstItem="ynK-dw-fFc" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="gIn-Ps-HEe"/>
<constraint firstAttribute="bottom" secondItem="6mt-ay-mAL" secondAttribute="bottom" id="lKc-RV-ybx"/>
<constraint firstAttribute="bottom" secondItem="ynK-dw-fFc" secondAttribute="bottom" id="qAW-TV-hHz"/>
<constraint firstItem="yvX-By-nNw" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="s2r-QB-ZQb"/>
<constraint firstItem="ynK-dw-fFc" firstAttribute="width" secondItem="m2S-Jp-Qdl" secondAttribute="width" multiplier="1:2" id="wsI-iB-DvJ"/>
</constraints>
</view>
<connections>
<outlet property="dropReceivingView" destination="0xW-mT-lME" id="cuR-H1-BKN"/>
<outlet property="identifierTextField" destination="yvX-By-nNw" id="pW5-lJ-8Cy"/>
<outlet property="inputTextView" destination="0xW-mT-lME" id="8Y7-yb-63r"/>
<outlet property="outputTextView" destination="GHT-gS-G1g" id="cVN-4m-knJ"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="76" y="726"/>
<point key="canvasLocation" x="75.5" y="726"/>
</scene>
</scenes>
</document>
@@ -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) }
}
}
@@ -12,9 +12,11 @@ import Cocoa
// MARK: - ViewController
class ViewController: NSViewController, NSTextViewDelegate {
class ViewController: NSViewController, NSTextViewDelegate, NSTextFieldDelegate {
private var textFieldObserver: Any?
@IBOutlet private var inputTextView: NSTextView!
@IBOutlet private var identifierTextField: NSTextField!
@IBOutlet private var outputTextView: NSTextView!
@IBOutlet private var dropReceivingView: DropAcceptingTextView!
@@ -28,12 +30,24 @@ class ViewController: NSViewController, NSTextViewDelegate {
self.dropReceivingView.handleDroppedFile = { [unowned self] url in
self.update(url: url)
}
self.textFieldObserver = NotificationCenter.default.addObserver(forName: NSTextField.textDidChangeNotification, object: self.identifierTextField, queue: .main) { [weak self] notification in
guard let self = self else { return }
self.identifierDidChange(self.identifierTextField)
}
}
// MARK: - NSTextViewDelegate
func textDidChange(_ notification: Notification) {
let string = inputTextView.string
let string = self.inputTextView.string
self.update(base64String: string)
}
// MARK: - Identifier Textfield
@IBAction func identifierDidChange(_ sender: NSTextField) {
let string = self.inputTextView.string
self.update(base64String: string)
}
@@ -57,7 +71,8 @@ private extension ViewController {
}
do {
let result = try AppReceiptValidator().parseUnofficialReceipt(origin: .data(data))
self.render(string: "\(result.receipt)\n\(result.unofficialReceipt)")
let validationResult = self.validateReceiptIfNecessary(data: data, macAddress: self.identifierTextField.stringValue) ?? "<Receipt not Validated, No Identifier provided, Supported: UUID, base64, MAC-Address>"
self.render(string: "\(validationResult)\n\n✅ Receipt Parsed\n\(result.receipt)\n\(result.unofficialReceipt)")
} catch {
self.render(string: "\(error)")
}
@@ -79,6 +94,26 @@ private extension ViewController {
}
}
func validateReceiptIfNecessary(data: Data, macAddress: String?) -> String? {
guard let macAddress = macAddress, macAddress.isEmpty == false else { return nil }
let sanitized = macAddress.trimmingCharacters(in: .whitespacesAndNewlines)
let deviceIdentifier = AppReceiptValidator.Parameters.DeviceIdentifier(macAddress: sanitized) ??
(UUID(uuidString: sanitized).flatMap { AppReceiptValidator.Parameters.DeviceIdentifier(uuid: $0) }) ??
AppReceiptValidator.Parameters.DeviceIdentifier(base64Encoded: sanitized)
guard let identifier = deviceIdentifier else { return "<Receipt not Validated\nIdentifier not parseable>" }
let parameters = AppReceiptValidator.Parameters(receiptOrigin: .data(data), shouldValidateSignaturePresence: true, signatureValidation: .shouldValidate(rootCertificateOrigin: .cerFileBundledWithAppReceiptValidator), shouldValidateHash: true, deviceIdentifier: identifier, propertyValidations: [])
let result = AppReceiptValidator().validateReceipt(parameters: parameters)
switch result {
case .success:
return "✅ Receipt Validated\nSignature and Hash Check successful"
case .error(let error, _, _):
return "❌ Receipt Invalid\n\(error)"
}
}
func render(string: String) {
self.outputTextView.string = string
}
@@ -0,0 +1,56 @@
//
// DeviceIdentifierTests.swift
// AppReceiptValidator
//
// Created by Hannes Oud on 22.11.18.
// Copyright © 2018 IdeasOnCanvas GmbH. All rights reserved.
//
@testable import AppReceiptValidator
import Foundation
import XCTest
final class DeviceIdentifierTests: XCTestCase {
func testBase64Initializer() {
let deviceIdentifier = AppReceiptValidator.Parameters.DeviceIdentifier(base64Encoded: "bEAItZRe")
XCTAssertNotNil(deviceIdentifier)
}
func testMacAddressInitializer() {
XCTAssertNotNil(AppReceiptValidator.Parameters.DeviceIdentifier(macAddress: "00:0d:3f:cd:02:5f"))
}
func testMacAddressInitializerOtherSeparator() {
XCTAssertNotNil(AppReceiptValidator.Parameters.DeviceIdentifier(macAddress: "00-0d-3f-cd-02-5f", separator: "-"))
}
func testUUIDInitializer() {
XCTAssertNotNil(AppReceiptValidator.Parameters.DeviceIdentifier(uuid: UUID()))
}
func testCurrent() {
let deviceIdentifierData = AppReceiptValidator.Parameters.DeviceIdentifier.currentDevice.getData()
XCTAssertNotNil(deviceIdentifierData)
}
#if os(macOS)
func testMacAddressRetrieval() {
guard let (data, string) = AppReceiptValidator.Parameters.DeviceIdentifier.getPrimaryNetworkMACAddress() else {
XCTFail("Failed to get device mac address")
return
}
guard let deviceIdentifierData = AppReceiptValidator.Parameters.DeviceIdentifier.currentDevice.getData() else {
XCTFail("Failed to get device mac address")
return
}
XCTAssertEqual(data, deviceIdentifierData)
guard let deviceIdentifierFromString = AppReceiptValidator.Parameters.DeviceIdentifier(macAddress: string) else {
XCTFail("Failed to get device identifier from mac address string")
return
}
XCTAssertEqual(deviceIdentifierFromString.getData(), deviceIdentifierData)
}
#endif
}
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
D114544621A6BDE6001BEC61 /* DeviceIdentifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D114544521A6BDE6001BEC61 /* DeviceIdentifierTests.swift */; };
D114544721A6BDE6001BEC61 /* DeviceIdentifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D114544521A6BDE6001BEC61 /* DeviceIdentifierTests.swift */; };
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 */; };
@@ -275,6 +277,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
D114544521A6BDE6001BEC61 /* DeviceIdentifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceIdentifierTests.swift; sourceTree = "<group>"; };
D13E5B7C20331B9B001880F0 /* DropAcceptingTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropAcceptingTextView.swift; 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>"; };
@@ -603,6 +606,7 @@
D1D6F5411F5D8A3800E86FE1 /* AppReceiptValidationTests.swift */,
D1AA845A1F6ABB31007F2558 /* AppReceiptPropertyValidationTests.swift */,
D150A0ED1F669A880026ED04 /* AppReceiptValidationInAppPurchaseTests.swift */,
D114544521A6BDE6001BEC61 /* DeviceIdentifierTests.swift */,
D1D6F5481F5D9B1100E86FE1 /* Tools */,
D1D6F5431F5D8DBC00E86FE1 /* Test Assets */,
);
@@ -1093,6 +1097,7 @@
D190957D1F6000A40095729B /* Sources */,
D190957E1F6000A40095729B /* Frameworks */,
D190957F1F6000A40095729B /* Resources */,
D1DEE48D20EBAEE800F95036 /* Swiftlint */,
);
buildRules = (
);
@@ -1148,7 +1153,6 @@
D1D6F4B11F5D684C00E86FE1 /* Frameworks */,
D1D6F4B21F5D684C00E86FE1 /* Headers */,
D1D6F4B31F5D684C00E86FE1 /* Resources */,
D1D6F52D1F5D872200E86FE1 /* Swiftlint */,
);
buildRules = (
);
@@ -1167,7 +1171,6 @@
D1D6F4BE1F5D687400E86FE1 /* Frameworks */,
D1D6F4BF1F5D687400E86FE1 /* Headers */,
D1D6F4C01F5D687400E86FE1 /* Resources */,
D1D6F52E1F5D872B00E86FE1 /* Swiftlint */,
);
buildRules = (
);
@@ -1186,6 +1189,7 @@
D1D6F4E11F5D691400E86FE1 /* Frameworks */,
D1D6F4E21F5D691400E86FE1 /* Resources */,
D1D6F5071F5D696800E86FE1 /* Embed Frameworks */,
D1DEE48C20EBAEC800F95036 /* Swiftlint */,
);
buildRules = (
);
@@ -1209,6 +1213,7 @@
TargetAttributes = {
D19095801F6000A40095729B = {
CreatedOnToolsVersion = 9.0;
LastSwiftMigration = 1000;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
@@ -1218,27 +1223,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;
};
};
@@ -1339,35 +1344,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 */
@@ -1390,6 +1403,7 @@
D19095CD1F601E960095729B /* AppReceiptValidationTests.swift in Sources */,
D1AA845D1F6ABB59007F2558 /* AppReceiptPropertyValidationTests.swift in Sources */,
D150A0EF1F669A880026ED04 /* AppReceiptValidationInAppPurchaseTests.swift in Sources */,
D114544721A6BDE6001BEC61 /* DeviceIdentifierTests.swift in Sources */,
D150A0F01F67E0990026ED04 /* Date+Convenience.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1402,6 +1416,7 @@
D19095CE1F601E980095729B /* AppReceiptValidationTests.swift in Sources */,
D1AA845C1F6ABB59007F2558 /* AppReceiptPropertyValidationTests.swift in Sources */,
D150A0EE1F669A880026ED04 /* AppReceiptValidationInAppPurchaseTests.swift in Sources */,
D114544621A6BDE6001BEC61 /* DeviceIdentifierTests.swift in Sources */,
D150A0F11F67E0990026ED04 /* Date+Convenience.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1514,7 +1529,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Debug;
};
@@ -1532,7 +1547,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Release;
};
@@ -1540,7 +1555,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;
@@ -1551,8 +1565,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;
};
@@ -1560,7 +1573,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;
@@ -1571,8 +1583,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;
};
@@ -1585,9 +1596,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;
};
@@ -1600,9 +1610,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;
};
@@ -1745,6 +1754,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 = "";
@@ -1774,6 +1784,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 = "";
@@ -1805,6 +1816,7 @@
PRODUCT_NAME = AppReceiptValidator;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -1835,6 +1847,7 @@
PRODUCT_NAME = AppReceiptValidator;
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -1852,7 +1865,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;
@@ -1868,7 +1881,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;
@@ -43,7 +43,9 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D19095A81F6001800095729B"
@@ -43,7 +43,9 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
skipped = "NO"
parallelizable = "YES"
testExecutionOrdering = "random">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D19095911F6000A40095729B"
@@ -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>
@@ -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>
@@ -83,7 +83,7 @@ public extension AppReceiptValidator.Parameters {
/// Used for calculating/validating the SHA1-Hash part of a receipt.
///
/// - currentDevice: Obtains it from the system location: MAC Adress on macOS, deviceIdentifierForVendor on iOS
/// - currentDevice: Obtains it from the system location: MAC Address on macOS, deviceIdentifierForVendor on iOS
/// - data: Specific Data to use
public enum DeviceIdentifier {
@@ -99,6 +99,20 @@ public extension AppReceiptValidator.Parameters {
self = .data(uuid.data)
}
/// Returns .data by parsing a MAC Address String
///
/// - Parameters:
/// - macAddress: A MAC Address of the form "00:0d:3f:cd:02:5f"
/// - separator: Defaults to `":"`
///
/// - Note: on macOS the MAC Addresses can be read from terminal command `ifconfig` looking for ther `ether` entry of `5e`.
public init?(macAddress: String, separator: String = ":") {
let bytes = macAddress.components(separatedBy: separator).compactMap { UInt8($0, radix: 16) }
guard bytes.count == 6 else { return nil }
self = .data(Data(bytes))
}
public func getData() -> Data? {
switch self {
case .data(let data):
@@ -20,7 +20,7 @@ extension AppReceiptValidator.Parameters.DeviceIdentifier {
/// Original implementation https://gist.github.com/mminer/82975d3781e2f42fc644d7fbfbf4f905
///
/// - Returns: The MAC Address as Data and String representation
private static func getPrimaryNetworkMACAddress() -> (data: Data, addressString: String)? {
static func getPrimaryNetworkMACAddress() -> (data: Data, addressString: String)? {
let matching = IOServiceMatching("IOEthernetInterface") as NSMutableDictionary
matching[kIOPropertyMatchKey] = ["IOPrimaryInterface": true]
var servicesIterator: io_iterator_t = 0
+1 -1
View File
@@ -2,7 +2,7 @@
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
![Platforms iOS, macOS](https://img.shields.io/badge/Platform-iOS%20|%20macOS-blue.svg "Platforms iOS, macOS")
![Language Swift](https://img.shields.io/badge/Language-Swift%204.1-orange.svg "Swift 4.1")
![Language Swift](https://img.shields.io/badge/Language-Swift%204.2-orange.svg "Swift 4.2")
[![License Apache 2.0 + OpenSSL](https://img.shields.io/badge/License-Apache%202.0%20|%20OpenSSL%20-aaaaff.svg "License")](LICENSE)
[![Build Status](https://travis-ci.org/IdeasOnCanvas/AppReceiptValidator.svg?branch=master)](https://travis-ci.org/IdeasOnCanvas/AppReceiptValidator)
[![Twitter: @hannesoid](https://img.shields.io/badge/Twitter-@hannesoid-red.svg?style=flat)](https://twitter.com/hannesoid)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 KiB

After

Width:  |  Height:  |  Size: 463 KiB