fix XCode config, add icons
@@ -0,0 +1,695 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
28BAEE044BE68A5986B97866 /* Pods_NFCPassportReaderApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7BD003B33886ED0F3F03325 /* Pods_NFCPassportReaderApp.framework */; };
|
||||
8C4EEF9CDD6DAFEF26F8909A /* Pods_NFCPassportReaderAppTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA39DA603B1A7EBD8FC38112 /* Pods_NFCPassportReaderAppTests.framework */; };
|
||||
A1298C9F25D53A5C00F5713E /* ViewExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1298C9E25D53A5C00F5713E /* ViewExt.swift */; };
|
||||
A1614B9225D5856600191749 /* ExportPassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1614B9125D5856600191749 /* ExportPassportView.swift */; };
|
||||
A16EB23122A9E9E10008F53F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16EB23022A9E9E10008F53F /* AppDelegate.swift */; };
|
||||
A16EB23322A9E9E10008F53F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16EB23222A9E9E10008F53F /* SceneDelegate.swift */; };
|
||||
A16EB23A22A9E9E20008F53F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A16EB23922A9E9E20008F53F /* Assets.xcassets */; };
|
||||
A16EB23D22A9E9E20008F53F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */; };
|
||||
A17134BE22C8EF7200C457C3 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17134BD22C8EF7100C457C3 /* MainView.swift */; };
|
||||
A17134C022C8F0A600C457C3 /* PassportUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17134BF22C8F0A600C457C3 /* PassportUtils.swift */; };
|
||||
A17375F525F78B0D005995DA /* PACETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17375F425F78B0C005995DA /* PACETests.swift */; };
|
||||
A1769DF725D3E318006002D1 /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1769DF625D3E318006002D1 /* SettingsStore.swift */; };
|
||||
A1816E9C22C9059F00F546A0 /* PassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1816E9B22C9059F00F546A0 /* PassportView.swift */; };
|
||||
A18248C22369D17300581384 /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A18248C12369D17300581384 /* DetailsView.swift */; };
|
||||
A182DE6125DD6F1300341204 /* StoredPassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A182DE6025DD6F1300341204 /* StoredPassportView.swift */; };
|
||||
A182DE6325DD730D00341204 /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A182DE6225DD730D00341204 /* FileManagerExt.swift */; };
|
||||
A182DE6825DD7EA600341204 /* MRZScannerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A182DE6725DD7EA600341204 /* MRZScannerViewController.swift */; };
|
||||
A1A13B9525B8A29E0026074C /* UIApplicationExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */; };
|
||||
A1A4C0F725B5E4D70070908B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4C0F625B5E4D70070908B /* Foundation.framework */; };
|
||||
A1C234C225DD19DE003FFD79 /* PassportSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */; };
|
||||
A1CE83AC22C91D1300E3EACF /* StringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1CE83AB22C91D1300E3EACF /* StringExt.swift */; };
|
||||
A1DD3F3F22C535F10067255C /* masterList.pem in Resources */ = {isa = PBXBuildFile; fileRef = A1DD3F3E22C535F00067255C /* masterList.pem */; };
|
||||
A1EBC5242370BAB2004DD19E /* DataGroupParsingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */; };
|
||||
A1EBC5252370BAB2004DD19E /* NFCPassportReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */; };
|
||||
A1FDC52E25D3F15D00D22FF4 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */; };
|
||||
A1FDC53225D3F19E00D22FF4 /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */; };
|
||||
A1FDC53425D3F1DE00D22FF4 /* CheckBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */; };
|
||||
A1FDC53625D43AB400D22FF4 /* MRZEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
A1EBC5122370B88D004DD19E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A16EB22522A9E9E10008F53F /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = A16EB22C22A9E9E10008F53F;
|
||||
remoteInfo = NFCPassportReaderApp;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
29684A8780D423313153D8B6 /* Pods-NFCPassportReaderAppTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NFCPassportReaderAppTests.release.xcconfig"; path = "Target Support Files/Pods-NFCPassportReaderAppTests/Pods-NFCPassportReaderAppTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
3B684038F7C81C32BA310074 /* Pods-NFCPassportReaderAppTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NFCPassportReaderAppTests.debug.xcconfig"; path = "Target Support Files/Pods-NFCPassportReaderAppTests/Pods-NFCPassportReaderAppTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
574315DEF74ED0B9CC6A8DC7 /* Pods-NFCPassportReaderApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NFCPassportReaderApp.debug.xcconfig"; path = "Target Support Files/Pods-NFCPassportReaderApp/Pods-NFCPassportReaderApp.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
A1095E982588FBB100D2A46A /* CHANGELOG */ = {isa = PBXFileReference; lastKnownFileType = text; name = CHANGELOG; path = ../../../CHANGELOG; sourceTree = "<group>"; };
|
||||
A1095E9B2589032D00D2A46A /* readme.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = readme.md; path = ../../readme.md; sourceTree = "<group>"; };
|
||||
A1298C9E25D53A5C00F5713E /* ViewExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExt.swift; sourceTree = "<group>"; };
|
||||
A1614B9125D5856600191749 /* ExportPassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportPassportView.swift; sourceTree = "<group>"; };
|
||||
A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NFCPassportReaderApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A16EB23022A9E9E10008F53F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
A16EB23222A9E9E10008F53F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
A16EB23922A9E9E20008F53F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
A16EB23C22A9E9E20008F53F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
A16EB23E22A9E9E20008F53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A16EB24422A9EA000008F53F /* NFCPassportReader.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NFCPassportReader.entitlements; sourceTree = "<group>"; };
|
||||
A17134BD22C8EF7100C457C3 /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||
A17134BF22C8F0A600C457C3 /* PassportUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PassportUtils.swift; sourceTree = "<group>"; };
|
||||
A17375F425F78B0C005995DA /* PACETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PACETests.swift; sourceTree = "<group>"; };
|
||||
A1769DF625D3E318006002D1 /* SettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStore.swift; sourceTree = "<group>"; };
|
||||
A1816E9B22C9059F00F546A0 /* PassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportView.swift; sourceTree = "<group>"; };
|
||||
A18248C12369D17300581384 /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
|
||||
A182DE6025DD6F1300341204 /* StoredPassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredPassportView.swift; sourceTree = "<group>"; };
|
||||
A182DE6225DD730D00341204 /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; };
|
||||
A182DE6725DD7EA600341204 /* MRZScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MRZScannerViewController.swift; sourceTree = "<group>"; };
|
||||
A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExt.swift; sourceTree = "<group>"; };
|
||||
A1A4C0F625B5E4D70070908B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportSummaryView.swift; sourceTree = "<group>"; };
|
||||
A1CE83AB22C91D1300E3EACF /* StringExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExt.swift; sourceTree = "<group>"; };
|
||||
A1DD3F3E22C535F00067255C /* masterList.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = masterList.pem; sourceTree = "<group>"; };
|
||||
A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NFCPassportReaderAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A1EBC5112370B88D004DD19E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataGroupParsingTests.swift; sourceTree = "<group>"; };
|
||||
A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NFCPassportReaderTests.swift; sourceTree = "<group>"; };
|
||||
A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
|
||||
A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxView.swift; sourceTree = "<group>"; };
|
||||
A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MRZEntryView.swift; sourceTree = "<group>"; };
|
||||
A7BD003B33886ED0F3F03325 /* Pods_NFCPassportReaderApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NFCPassportReaderApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B239DD4BD3AA9ECF4F595D22 /* Pods-NFCPassportReaderApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NFCPassportReaderApp.release.xcconfig"; path = "Target Support Files/Pods-NFCPassportReaderApp/Pods-NFCPassportReaderApp.release.xcconfig"; sourceTree = "<group>"; };
|
||||
DA39DA603B1A7EBD8FC38112 /* Pods_NFCPassportReaderAppTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NFCPassportReaderAppTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
A16EB22A22A9E9E10008F53F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A1A4C0F725B5E4D70070908B /* Foundation.framework in Frameworks */,
|
||||
28BAEE044BE68A5986B97866 /* Pods_NFCPassportReaderApp.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC50A2370B88D004DD19E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8C4EEF9CDD6DAFEF26F8909A /* Pods_NFCPassportReaderAppTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
A1298C9B25D539CD00F5713E /* HelperViews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */,
|
||||
A1298C9E25D53A5C00F5713E /* ViewExt.swift */,
|
||||
A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */,
|
||||
);
|
||||
path = HelperViews;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22422A9E9E10008F53F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A16EB22F22A9E9E10008F53F /* NFCPassportReaderApp */,
|
||||
A1EBC50E2370B88D004DD19E /* NFCPassportReaderAppTests */,
|
||||
A16EB22E22A9E9E10008F53F /* Products */,
|
||||
EE354654AF07CDA5F9366735 /* Pods */,
|
||||
A1A4C0E325B5D3370070908B /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22E22A9E9E10008F53F /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */,
|
||||
A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22F22A9E9E10008F53F /* NFCPassportReaderApp */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A16EB24422A9EA000008F53F /* NFCPassportReader.entitlements */,
|
||||
A1CE83AF22C91DB600E3EACF /* Model */,
|
||||
A182DE6425DD731900341204 /* Extensions */,
|
||||
A1CE83B022C91DF100E3EACF /* Views */,
|
||||
A16EB23022A9E9E10008F53F /* AppDelegate.swift */,
|
||||
A16EB23222A9E9E10008F53F /* SceneDelegate.swift */,
|
||||
A16EB23922A9E9E20008F53F /* Assets.xcassets */,
|
||||
A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */,
|
||||
A16EB23E22A9E9E20008F53F /* Info.plist */,
|
||||
A1DD3F3E22C535F00067255C /* masterList.pem */,
|
||||
A1095E982588FBB100D2A46A /* CHANGELOG */,
|
||||
A1095E9B2589032D00D2A46A /* readme.md */,
|
||||
);
|
||||
path = NFCPassportReaderApp;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A182DE6425DD731900341204 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1CE83AB22C91D1300E3EACF /* StringExt.swift */,
|
||||
A182DE6225DD730D00341204 /* FileManagerExt.swift */,
|
||||
A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1A4C0E325B5D3370070908B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1A4C0F625B5E4D70070908B /* Foundation.framework */,
|
||||
A7BD003B33886ED0F3F03325 /* Pods_NFCPassportReaderApp.framework */,
|
||||
DA39DA603B1A7EBD8FC38112 /* Pods_NFCPassportReaderAppTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1CE83AF22C91DB600E3EACF /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A17134BF22C8F0A600C457C3 /* PassportUtils.swift */,
|
||||
A1769DF625D3E318006002D1 /* SettingsStore.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1CE83B022C91DF100E3EACF /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1298C9B25D539CD00F5713E /* HelperViews */,
|
||||
A17134BD22C8EF7100C457C3 /* MainView.swift */,
|
||||
A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */,
|
||||
A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */,
|
||||
A1816E9B22C9059F00F546A0 /* PassportView.swift */,
|
||||
A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */,
|
||||
A18248C12369D17300581384 /* DetailsView.swift */,
|
||||
A182DE6025DD6F1300341204 /* StoredPassportView.swift */,
|
||||
A1614B9125D5856600191749 /* ExportPassportView.swift */,
|
||||
A182DE6725DD7EA600341204 /* MRZScannerViewController.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1EBC50E2370B88D004DD19E /* NFCPassportReaderAppTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */,
|
||||
A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */,
|
||||
A1EBC5112370B88D004DD19E /* Info.plist */,
|
||||
A17375F425F78B0C005995DA /* PACETests.swift */,
|
||||
);
|
||||
path = NFCPassportReaderAppTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EE354654AF07CDA5F9366735 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
574315DEF74ED0B9CC6A8DC7 /* Pods-NFCPassportReaderApp.debug.xcconfig */,
|
||||
B239DD4BD3AA9ECF4F595D22 /* Pods-NFCPassportReaderApp.release.xcconfig */,
|
||||
3B684038F7C81C32BA310074 /* Pods-NFCPassportReaderAppTests.debug.xcconfig */,
|
||||
29684A8780D423313153D8B6 /* Pods-NFCPassportReaderAppTests.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A16EB24122A9E9E20008F53F /* Build configuration list for PBXNativeTarget "NFCPassportReaderApp" */;
|
||||
buildPhases = (
|
||||
441F58E6FEE1B28C771C6B72 /* [CP] Check Pods Manifest.lock */,
|
||||
A16EB22922A9E9E10008F53F /* Sources */,
|
||||
A16EB22A22A9E9E10008F53F /* Frameworks */,
|
||||
A16EB22B22A9E9E10008F53F /* Resources */,
|
||||
4E62328E60F074D699104549 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = NFCPassportReaderApp;
|
||||
productName = NFCTest;
|
||||
productReference = A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
A1EBC50C2370B88D004DD19E /* NFCPassportReaderAppTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A1EBC5162370B88D004DD19E /* Build configuration list for PBXNativeTarget "NFCPassportReaderAppTests" */;
|
||||
buildPhases = (
|
||||
11A5FABC15C673E24DA3F0C2 /* [CP] Check Pods Manifest.lock */,
|
||||
A1EBC5092370B88D004DD19E /* Sources */,
|
||||
A1EBC50A2370B88D004DD19E /* Frameworks */,
|
||||
A1EBC50B2370B88D004DD19E /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
A1EBC5132370B88D004DD19E /* PBXTargetDependency */,
|
||||
);
|
||||
name = NFCPassportReaderAppTests;
|
||||
productName = NFCPassportReaderAppTests;
|
||||
productReference = A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
A16EB22522A9E9E10008F53F /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1120;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "Andy Qua";
|
||||
TargetAttributes = {
|
||||
A16EB22C22A9E9E10008F53F = {
|
||||
CreatedOnToolsVersion = 11.0;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
A1EBC50C2370B88D004DD19E = {
|
||||
CreatedOnToolsVersion = 11.2;
|
||||
TestTargetID = A16EB22C22A9E9E10008F53F;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = A16EB22822A9E9E10008F53F /* Build configuration list for PBXProject "NFCPassportReaderApp" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = A16EB22422A9E9E10008F53F;
|
||||
productRefGroup = A16EB22E22A9E9E10008F53F /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */,
|
||||
A1EBC50C2370B88D004DD19E /* NFCPassportReaderAppTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
A16EB22B22A9E9E10008F53F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A16EB23D22A9E9E20008F53F /* LaunchScreen.storyboard in Resources */,
|
||||
A1DD3F3F22C535F10067255C /* masterList.pem in Resources */,
|
||||
A16EB23A22A9E9E20008F53F /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC50B2370B88D004DD19E /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
11A5FABC15C673E24DA3F0C2 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-NFCPassportReaderAppTests-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
441F58E6FEE1B28C771C6B72 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-NFCPassportReaderApp-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
4E62328E60F074D699104549 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-NFCPassportReaderApp/Pods-NFCPassportReaderApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-NFCPassportReaderApp/Pods-NFCPassportReaderApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NFCPassportReaderApp/Pods-NFCPassportReaderApp-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
A16EB22922A9E9E10008F53F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A182DE6825DD7EA600341204 /* MRZScannerViewController.swift in Sources */,
|
||||
A1CE83AC22C91D1300E3EACF /* StringExt.swift in Sources */,
|
||||
A1FDC53625D43AB400D22FF4 /* MRZEntryView.swift in Sources */,
|
||||
A17134BE22C8EF7200C457C3 /* MainView.swift in Sources */,
|
||||
A16EB23122A9E9E10008F53F /* AppDelegate.swift in Sources */,
|
||||
A1816E9C22C9059F00F546A0 /* PassportView.swift in Sources */,
|
||||
A1769DF725D3E318006002D1 /* SettingsStore.swift in Sources */,
|
||||
A1298C9F25D53A5C00F5713E /* ViewExt.swift in Sources */,
|
||||
A182DE6325DD730D00341204 /* FileManagerExt.swift in Sources */,
|
||||
A1FDC52E25D3F15D00D22FF4 /* SettingsView.swift in Sources */,
|
||||
A182DE6125DD6F1300341204 /* StoredPassportView.swift in Sources */,
|
||||
A1FDC53225D3F19E00D22FF4 /* ViewModifiers.swift in Sources */,
|
||||
A1C234C225DD19DE003FFD79 /* PassportSummaryView.swift in Sources */,
|
||||
A1614B9225D5856600191749 /* ExportPassportView.swift in Sources */,
|
||||
A18248C22369D17300581384 /* DetailsView.swift in Sources */,
|
||||
A1FDC53425D3F1DE00D22FF4 /* CheckBoxView.swift in Sources */,
|
||||
A1A13B9525B8A29E0026074C /* UIApplicationExt.swift in Sources */,
|
||||
A16EB23322A9E9E10008F53F /* SceneDelegate.swift in Sources */,
|
||||
A17134C022C8F0A600C457C3 /* PassportUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC5092370B88D004DD19E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A1EBC5252370BAB2004DD19E /* NFCPassportReaderTests.swift in Sources */,
|
||||
A17375F525F78B0D005995DA /* PACETests.swift in Sources */,
|
||||
A1EBC5242370BAB2004DD19E /* DataGroupParsingTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
A1EBC5132370B88D004DD19E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */;
|
||||
targetProxy = A1EBC5122370B88D004DD19E /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
A16EB23C22A9E9E20008F53F /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
A16EB23F22A9E9E20008F53F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
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;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A16EB24022A9E9E20008F53F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
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;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A16EB24222A9E9E20008F53F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 574315DEF74ED0B9CC6A8DC7 /* Pods-NFCPassportReaderApp.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NFCPassportReaderApp/NFCPassportReader.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4.1;
|
||||
DEVELOPMENT_TEAM = BV8DN58CD3;
|
||||
INFOPLIST_FILE = NFCPassportReaderApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iag.nfcpassportreader;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A16EB24322A9E9E20008F53F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B239DD4BD3AA9ECF4F595D22 /* Pods-NFCPassportReaderApp.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NFCPassportReaderApp/NFCPassportReader.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 4.1;
|
||||
DEVELOPMENT_TEAM = BV8DN58CD3;
|
||||
INFOPLIST_FILE = NFCPassportReaderApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.iag.nfcpassportreader;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A1EBC5142370B88D004DD19E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3B684038F7C81C32BA310074 /* Pods-NFCPassportReaderAppTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.NFCPassportReaderAppTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NFCPassportReaderApp.app/NFCPassportReaderApp";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A1EBC5152370B88D004DD19E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 29684A8780D423313153D8B6 /* Pods-NFCPassportReaderAppTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.NFCPassportReaderAppTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NFCPassportReaderApp.app/NFCPassportReaderApp";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
A16EB22822A9E9E10008F53F /* Build configuration list for PBXProject "NFCPassportReaderApp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A16EB23F22A9E9E20008F53F /* Debug */,
|
||||
A16EB24022A9E9E20008F53F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A16EB24122A9E9E20008F53F /* Build configuration list for PBXNativeTarget "NFCPassportReaderApp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A16EB24222A9E9E20008F53F /* Debug */,
|
||||
A16EB24322A9E9E20008F53F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A1EBC5162370B88D004DD19E /* Build configuration list for PBXNativeTarget "NFCPassportReaderAppTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A1EBC5142370B88D004DD19E /* Debug */,
|
||||
A1EBC5152370B88D004DD19E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = A16EB22522A9E9E10008F53F /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NFCPassportReaderTests"
|
||||
BuildableName = "NFCPassportReaderTests"
|
||||
BlueprintName = "NFCPassportReaderTests"
|
||||
ReferencedContainer = "container:..">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A1EBC50C2370B88D004DD19E"
|
||||
BuildableName = "NFCPassportReaderAppTests.xctest"
|
||||
BlueprintName = "NFCPassportReaderAppTests"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
disableMainThreadChecker = "YES"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "OS_ACTIVITY_MODE"
|
||||
value = "disable"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
10
app/ios/Examples/Example_CocoaPods/NFCPassportReaderApp.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:NFCPassportReaderApp.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 06/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreNFC
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
// Called when a new scene session is being created.
|
||||
// Use this method to select a configuration to create the new scene with.
|
||||
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
// Called when the user discards a scene session.
|
||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"images" : [
|
||||
{
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-40.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-40@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-60@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-72.png",
|
||||
"size" : "72x72",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"idiom" : "ipad",
|
||||
"size" : "72x72",
|
||||
"filename" : "icon-72@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x",
|
||||
"filename" : "icon-76.png"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-76@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "50x50",
|
||||
"filename" : "icon-small-50.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-small-50@2x.png",
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"scale" : "1x",
|
||||
"filename" : "icon-small.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-small@2x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "57x57",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon@2x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-small@3x.png",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"scale" : "3x",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-40@3x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-60@3x.png",
|
||||
"scale" : "3x",
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"scale" : "1x",
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"filename" : "icon-small.png"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-small@2x.png",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-83.5@2x.png",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"filename" : "notification-icon@2x.png",
|
||||
"idiom" : "iphone"
|
||||
},
|
||||
{
|
||||
"scale" : "3x",
|
||||
"filename" : "notification-icon@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "notification-icon~ipad.png",
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "notification-icon~ipad@2x.png",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"filename" : "ios-marketing.png",
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 370 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 723 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "background.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 387 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "head.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
app/ios/Examples/Example_CocoaPods/NFCPassportReaderApp/Assets.xcassets/head.imageset/head.png
vendored
Normal file
|
After Width: | Height: | Size: 187 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FileManagerExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 17/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension FileManager {
|
||||
static var cachesFolder : URL {
|
||||
FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// StringExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 30/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Some Utility methods for string - access characters by index
|
||||
extension String {
|
||||
subscript(_ i: Int) -> String {
|
||||
let idx1 = index(startIndex, offsetBy: i)
|
||||
let idx2 = index(idx1, offsetBy: 1)
|
||||
return String(self[idx1..<idx2])
|
||||
}
|
||||
|
||||
subscript (bounds: CountableRange<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
return String(self[start..<end])
|
||||
}
|
||||
|
||||
subscript (bounds: CountableClosedRange<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
return String(self[start...end])
|
||||
}
|
||||
|
||||
subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
return String(self[start...])
|
||||
}
|
||||
|
||||
func strip() -> String {
|
||||
let trimmed = self.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// UIApplicationExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 20/01/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIApplication {
|
||||
static var release: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String? ?? "x.x"
|
||||
}
|
||||
static var build: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String? ?? "x"
|
||||
}
|
||||
static var version: String {
|
||||
return "\(release).\(build)"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>NFCPassportReaderApp</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NFCReaderUsageDescription</key>
|
||||
<string>This app uses NFC to scan passports</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app uses the camera to read passports</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>nfc</string>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
|
||||
<array>
|
||||
<string>A0000002471001</string>
|
||||
<string>A0000002472001</string>
|
||||
<string>00000000000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// PassportUtils.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 30/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import NFCPassportReader
|
||||
|
||||
class PassportUtils {
|
||||
|
||||
func getMRZKey(passportNumber: String, dateOfBirth: String, dateOfExpiry: String ) -> String {
|
||||
|
||||
// Pad fields if necessary
|
||||
let pptNr = pad( passportNumber, fieldLength:9)
|
||||
let dob = pad( dateOfBirth, fieldLength:6)
|
||||
let exp = pad( dateOfExpiry, fieldLength:6)
|
||||
|
||||
// Calculate checksums
|
||||
let passportNrChksum = calcCheckSum(pptNr)
|
||||
let dateOfBirthChksum = calcCheckSum(dob)
|
||||
let expiryDateChksum = calcCheckSum(exp)
|
||||
|
||||
let mrzKey = "\(pptNr)\(passportNrChksum)\(dob)\(dateOfBirthChksum)\(exp)\(expiryDateChksum)"
|
||||
|
||||
return mrzKey
|
||||
}
|
||||
|
||||
func pad( _ value : String, fieldLength:Int ) -> String {
|
||||
// Pad out field lengths with < if they are too short
|
||||
let paddedValue = (value + String(repeating: "<", count: fieldLength)).prefix(fieldLength)
|
||||
return String(paddedValue)
|
||||
}
|
||||
|
||||
func calcCheckSum( _ checkString : String ) -> Int {
|
||||
let characterDict = ["0" : "0", "1" : "1", "2" : "2", "3" : "3", "4" : "4", "5" : "5", "6" : "6", "7" : "7", "8" : "8", "9" : "9", "<" : "0", " " : "0", "A" : "10", "B" : "11", "C" : "12", "D" : "13", "E" : "14", "F" : "15", "G" : "16", "H" : "17", "I" : "18", "J" : "19", "K" : "20", "L" : "21", "M" : "22", "N" : "23", "O" : "24", "P" : "25", "Q" : "26", "R" : "27", "S" : "28","T" : "29", "U" : "30", "V" : "31", "W" : "32", "X" : "33", "Y" : "34", "Z" : "35"]
|
||||
|
||||
var sum = 0
|
||||
var m = 0
|
||||
let multipliers : [Int] = [7, 3, 1]
|
||||
for c in checkString {
|
||||
guard let lookup = characterDict["\(c)"],
|
||||
let number = Int(lookup) else { return 0 }
|
||||
let product = number * multipliers[m]
|
||||
sum += product
|
||||
m = (m+1) % 3
|
||||
}
|
||||
|
||||
return (sum % 10)
|
||||
}
|
||||
|
||||
static func shareLogs() {
|
||||
do {
|
||||
let arr = Log.logData
|
||||
let data = try JSONSerialization.data(withJSONObject: arr, options: .prettyPrinted)
|
||||
|
||||
let temporaryURL = URL(fileURLWithPath: NSTemporaryDirectory() + "passportreader.log")
|
||||
try data.write(to: temporaryURL)
|
||||
|
||||
let av = UIActivityViewController(activityItems: [temporaryURL], applicationActivities: nil)
|
||||
let keyWindow = UIApplication.shared.connectedScenes
|
||||
.filter({$0.activationState == .foregroundActive})
|
||||
.map({$0 as? UIWindowScene})
|
||||
.compactMap({$0})
|
||||
.first?.windows
|
||||
.filter({$0.isKeyWindow}).first
|
||||
|
||||
keyWindow?.rootViewController?.present(av, animated: true, completion: nil)
|
||||
} catch {
|
||||
print( "ERROR - \(error)" )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// SettingsStore.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 10/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import NFCPassportReader
|
||||
|
||||
final class SettingsStore: ObservableObject {
|
||||
|
||||
private enum Keys {
|
||||
static let captureLog = "captureLog"
|
||||
static let logLevel = "logLevel"
|
||||
static let useNewVerification = "useNewVerification"
|
||||
static let savePassportOnScan = "savePassportOnScan"
|
||||
static let passportNumber = "passportNumber"
|
||||
static let dateOfBirth = "dateOfBirth"
|
||||
static let dateOfExpiry = "dateOfExpiry"
|
||||
|
||||
static let allVals = [captureLog, logLevel, useNewVerification, passportNumber, dateOfBirth, dateOfExpiry]
|
||||
}
|
||||
|
||||
private let cancellable: Cancellable
|
||||
private let defaults: UserDefaults
|
||||
|
||||
let objectWillChange = PassthroughSubject<Void, Never>()
|
||||
|
||||
init(defaults: UserDefaults = .standard) {
|
||||
self.defaults = defaults
|
||||
|
||||
|
||||
defaults.register(defaults: [
|
||||
Keys.captureLog: true,
|
||||
Keys.logLevel: 1,
|
||||
Keys.useNewVerification: true,
|
||||
Keys.savePassportOnScan: false,
|
||||
Keys.passportNumber: "",
|
||||
Keys.dateOfBirth: Date().timeIntervalSince1970,
|
||||
Keys.dateOfExpiry: Date().timeIntervalSince1970,
|
||||
])
|
||||
|
||||
cancellable = NotificationCenter.default
|
||||
.publisher(for: UserDefaults.didChangeNotification)
|
||||
.map { _ in () }
|
||||
.subscribe(objectWillChange)
|
||||
}
|
||||
|
||||
func reset() {
|
||||
if let bundleID = Bundle.main.bundleIdentifier {
|
||||
UserDefaults.standard.removePersistentDomain(forName: bundleID)
|
||||
}
|
||||
}
|
||||
|
||||
var shouldCaptureLogs: Bool {
|
||||
set { defaults.set(newValue, forKey: Keys.captureLog) }
|
||||
get { defaults.bool(forKey: Keys.captureLog) }
|
||||
}
|
||||
|
||||
var logLevel: LogLevel {
|
||||
get {
|
||||
return LogLevel(rawValue:defaults.integer(forKey: Keys.logLevel)) ?? .info
|
||||
}
|
||||
set {
|
||||
defaults.set(newValue.rawValue, forKey: Keys.logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
var useNewVerificationMethod: Bool {
|
||||
set { defaults.set(newValue, forKey: Keys.useNewVerification) }
|
||||
get { defaults.bool(forKey: Keys.useNewVerification) }
|
||||
}
|
||||
|
||||
var savePassportOnScan: Bool {
|
||||
set { defaults.set(newValue, forKey: Keys.savePassportOnScan) }
|
||||
get { defaults.bool(forKey: Keys.savePassportOnScan) }
|
||||
}
|
||||
|
||||
var passportNumber: String {
|
||||
set { defaults.set(newValue, forKey: Keys.passportNumber) }
|
||||
get { defaults.string(forKey: Keys.passportNumber) ?? "" }
|
||||
}
|
||||
|
||||
var dateOfBirth: Date {
|
||||
set {
|
||||
defaults.set(newValue.timeIntervalSince1970, forKey: Keys.dateOfBirth)
|
||||
}
|
||||
get {
|
||||
let d = Date(timeIntervalSince1970: defaults.double(forKey: Keys.dateOfBirth))
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
var dateOfExpiry: Date {
|
||||
set {
|
||||
defaults.set(newValue.timeIntervalSince1970, forKey: Keys.dateOfExpiry) }
|
||||
get {
|
||||
let d = Date(timeIntervalSince1970: defaults.double(forKey: Keys.dateOfExpiry))
|
||||
return d
|
||||
}
|
||||
}
|
||||
|
||||
@Published var passport : NFCPassportModel?
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.nfc.readersession.formats</key>
|
||||
<array>
|
||||
<string>TAG</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// SceneDelegate.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 06/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
var settings = SettingsStore()
|
||||
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
|
||||
// Use a UIHostingController as window root view controller
|
||||
if let windowScene = scene as? UIWindowScene {
|
||||
let window = UIWindow(windowScene: windowScene)
|
||||
window.rootViewController = UIHostingController(rootView: MainView().environmentObject(settings))
|
||||
self.window = window
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
|
||||
func sceneDidDisconnect(_ scene: UIScene) {
|
||||
// Called as the scene is being released by the system.
|
||||
// This occurs shortly after the scene enters the background, or when its session is discarded.
|
||||
// Release any resources associated with this scene that can be re-created the next time the scene connects.
|
||||
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
|
||||
}
|
||||
|
||||
func sceneDidBecomeActive(_ scene: UIScene) {
|
||||
// Called when the scene has moved from an inactive state to an active state.
|
||||
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
|
||||
}
|
||||
|
||||
func sceneWillResignActive(_ scene: UIScene) {
|
||||
// Called when the scene will move from an active state to an inactive state.
|
||||
// This may occur due to temporary interruptions (ex. an incoming phone call).
|
||||
}
|
||||
|
||||
func sceneWillEnterForeground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the background to the foreground.
|
||||
// Use this method to undo the changes made on entering the background.
|
||||
}
|
||||
|
||||
func sceneDidEnterBackground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// DetailsView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 30/10/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct Item : Identifiable {
|
||||
var id = UUID()
|
||||
var title : String
|
||||
var value : String
|
||||
|
||||
var textColor : Color {
|
||||
return value.hasPrefix("FAILED") ? Color.red : Color.primary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct DetailsView : View {
|
||||
private var passport: NFCPassportModel
|
||||
private var sectionNames = ["Chip information", "Verification information", "Document signing certificate", "Country signing certificate", "Security Info details", "Datagroup Hashes"]
|
||||
private var sections = [[Item]]()
|
||||
|
||||
init( passport : NFCPassportModel ) {
|
||||
self.passport = passport
|
||||
sections.append(getChipInfoSection(self.passport))
|
||||
sections.append(getVerificationDetailsSection(self.passport))
|
||||
sections.append(getCertificateSigningCertDetails(certItems:self.passport.documentSigningCertificate?.getItemsAsDict()))
|
||||
sections.append(getCertificateSigningCertDetails(certItems:self.passport.countrySigningCertificate?.getItemsAsDict()))
|
||||
sections.append(getSecurityInfosSection(self.passport))
|
||||
sections.append(getDataGroupHashesSection(self.passport))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
List {
|
||||
ForEach( 0 ..< self.sectionNames.count ) { i in
|
||||
if self.sections[i].count > 0 {
|
||||
SectionGroup(sectionTitle: self.sectionNames[i], items: self.sections[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getChipInfoSection(_ passport: NFCPassportModel) -> [Item] {
|
||||
// Build Chip info section
|
||||
let chipInfo = [Item(title:"LDS Version", value: passport.LDSVersion),
|
||||
Item(title:"Data groups present", value: passport.dataGroupsPresent.joined(separator: ", ")),
|
||||
Item(title:"Data groups read", value: passport.dataGroupsAvailable.map { $0.getName()}.joined(separator: ", "))]
|
||||
|
||||
return chipInfo
|
||||
}
|
||||
|
||||
func getVerificationDetailsSection(_ passport: NFCPassportModel) -> [Item] {
|
||||
// Build Verification Info section
|
||||
var activeAuth : String = "Not supported"
|
||||
if passport.activeAuthenticationSupported {
|
||||
activeAuth = passport.activeAuthenticationPassed ? "SUCCESS\nSignature verified" : "FAILED\nCould not verify signature"
|
||||
}
|
||||
var chipAuth : String = "Not supported"
|
||||
if passport.isChipAuthenticationSupported {
|
||||
switch( passport.chipAuthenticationStatus ) {
|
||||
case .notDone:
|
||||
chipAuth = "Supported - Not done"
|
||||
case .success:
|
||||
chipAuth = "SUCCESS\nSignature verified"
|
||||
case .failed:
|
||||
chipAuth = "FAILED\nCould not verify signature"
|
||||
}
|
||||
}
|
||||
|
||||
var authType : String = "Authentication not done"
|
||||
if passport.PACEStatus == .success {
|
||||
authType = "PACE"
|
||||
} else if passport.BACStatus == .success {
|
||||
authType = "BAC"
|
||||
}
|
||||
|
||||
// Do PACE Info
|
||||
var paceStatus = "Not Supported"
|
||||
if passport.isPACESupported {
|
||||
switch( passport.PACEStatus ) {
|
||||
case .notDone:
|
||||
paceStatus = "Supported - Not done"
|
||||
case .success:
|
||||
paceStatus = "SUCCESS"
|
||||
case .failed:
|
||||
paceStatus = "FAILED"
|
||||
}
|
||||
}
|
||||
|
||||
let verificationDetails : [Item] = [
|
||||
Item(title: "Access Control", value: authType),
|
||||
Item(title: "PACE", value: paceStatus),
|
||||
Item(title: "Chip Authentication", value: chipAuth),
|
||||
Item(title: "Active Authentication", value: activeAuth),
|
||||
Item(title: "Document Signing Certificate", value: passport.documentSigningCertificateVerified ? "SUCCESS\nSOD Signature verified" : "FAILED\nCouldn't verify SOD signature"),
|
||||
Item(title: "Country signing Certificate", value: passport.passportCorrectlySigned ? "SUCCESS\nmatched to country signing certificate" : "FAILED\nCouldn't build trust chain"),
|
||||
Item(title: "Data group hashes", value: passport.passportDataNotTampered ? "SUCCESS\nAll hashes match" : "FAILED\nCouldn't match hashes" )
|
||||
]
|
||||
|
||||
return verificationDetails
|
||||
}
|
||||
|
||||
func getCertificateSigningCertDetails( certItems : [CertificateItem : String]? ) -> [Item] {
|
||||
let titles : [String] = ["Serial number", "Signature algorithm", "Public key algorithm", "Certificate fingerprint", "Issuer", "Subject", "Valid from", "Valid to"]
|
||||
|
||||
var items = [Item]()
|
||||
if certItems?.count ?? 0 == 0 {
|
||||
items.append( Item(title:"Certificate details", value: "NOT FOUND" ) )
|
||||
} else {
|
||||
for title in titles {
|
||||
let ci = CertificateItem(rawValue:title)!
|
||||
items.append( Item(title:title, value: certItems?[ci] ?? "") )
|
||||
}
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func getDataGroupHashesSection(_ passport: NFCPassportModel) -> [Item] {
|
||||
var dgHashes = [Item]()
|
||||
for id in DataGroupId.allCases {
|
||||
if let hash = passport.dataGroupHashes[id] {
|
||||
dgHashes.append( Item(title:hash.id, value:hash.match ? "MATCHED" : "UNMATCHED"))
|
||||
dgHashes.append( Item(title:"SOD Hash", value: hash.sodHash))
|
||||
dgHashes.append( Item(title:"Computed Hash", value: hash.computedHash))
|
||||
}
|
||||
}
|
||||
return dgHashes
|
||||
}
|
||||
|
||||
func getSecurityInfosSection( _ passport : NFCPassportModel) -> [Item] {
|
||||
guard let dg14 = passport.getDataGroup(.DG14) as? DataGroup14 else { return [] }
|
||||
|
||||
var items = [Item]()
|
||||
for secInfo in dg14.securityInfos {
|
||||
var title : String = ""
|
||||
var value : String = ""
|
||||
if let cai = secInfo as? ChipAuthenticationInfo {
|
||||
title = "ChipAuthenticationInfo"
|
||||
value = "\(secInfo.getProtocolOIDString())\n\(secInfo.getObjectIdentifier())\nUses Key Id: \(cai.getKeyId())"
|
||||
} else if let capki = secInfo as? ChipAuthenticationPublicKeyInfo {
|
||||
title = "ChipAuthenticationPublicKeyInfo"
|
||||
value = "\(secInfo.getProtocolOIDString())\n\(secInfo.getObjectIdentifier())\nKey Id: \(capki.getKeyId())"
|
||||
} else if let pacei = secInfo as? PACEInfo {
|
||||
title = "PACEInfo"
|
||||
value = "\(pacei.getProtocolOIDString())\n\(pacei.getObjectIdentifier())\nParameter ID: \(pacei.getParameterId() ?? -1)"
|
||||
} else if let activeAuthInfo = secInfo as? ActiveAuthenticationInfo {
|
||||
title = "ActiveAuthenticationInfo"
|
||||
value =
|
||||
"\(activeAuthInfo.getProtocolOIDString())\n\(activeAuthInfo.getSignatureAlgorithmOIDString() ?? "")"
|
||||
}
|
||||
|
||||
items.append( Item(title:title, value: value))
|
||||
|
||||
}
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
struct SectionGroup : View {
|
||||
var sectionTitle : String
|
||||
var items : [Item]
|
||||
|
||||
var body: some View {
|
||||
Section(header: Text(sectionTitle)) {
|
||||
ForEach(self.items) { item in
|
||||
VStack(alignment:.leading, spacing:0) {
|
||||
Text(item.title)
|
||||
.font(.headline)
|
||||
Text(item.value)
|
||||
.foregroundColor(item.textColor)
|
||||
.lineLimit(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct DetailsView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
let passport = NFCPassportModel()
|
||||
return DetailsView(passport:passport)
|
||||
.environmentObject(settings)
|
||||
.environment( \.colorScheme, .light)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// ExportPassportView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 11/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct MultipleSelectionRow: View {
|
||||
var title: String
|
||||
var isSelected: Bool
|
||||
var action: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: self.action) {
|
||||
HStack {
|
||||
Text(self.title)
|
||||
if self.isSelected {
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
}
|
||||
}
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
}
|
||||
|
||||
struct ExportPassportView: View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
|
||||
@State var items: [DataGroupId] = []
|
||||
@State var selections: [DataGroupId] = []
|
||||
@State var isAASupported : Bool = false
|
||||
@State var includeAA : Bool = false
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Select Passport items to export"), footer:Text("* contains personal information")) {
|
||||
List {
|
||||
ForEach(items, id: \.self) { item in
|
||||
MultipleSelectionRow(title: dgToText(item), isSelected: self.selections.contains(item)) {
|
||||
if self.selections.contains(item) {
|
||||
self.selections.removeAll(where: { $0 == item })
|
||||
}
|
||||
else {
|
||||
self.selections.append(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isAASupported {
|
||||
Toggle("Include Active Authentication Challenge/Response?", isOn: $includeAA)
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
}
|
||||
Button(action: {
|
||||
sharePassport()
|
||||
}, label: {
|
||||
Text("Export selected passport details")
|
||||
.font(.title3)
|
||||
})
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.navigationTitle("Export passport")
|
||||
.onAppear() {
|
||||
if let passport = settings.passport {
|
||||
items = [.SOD, .COM]
|
||||
items.append(contentsOf: DataGroupId.allCases.filter { passport.dataGroupsAvailable.contains($0) } )
|
||||
|
||||
// Default select only the DGs that contain no personal info.
|
||||
selections = [.SOD, .COM, .DG14, .DG15]
|
||||
isAASupported = passport.activeAuthenticationSupported
|
||||
if isAASupported {
|
||||
includeAA = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ExportPassportView {
|
||||
func sharePassport() {
|
||||
do {
|
||||
let dict = settings.passport!.dumpPassportData( selectedDataGroups:selections,includeActiveAuthenticationData: includeAA)
|
||||
let data = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
|
||||
|
||||
let temporaryURL = URL(fileURLWithPath: NSTemporaryDirectory() + "passport.json")
|
||||
try data.write(to: temporaryURL)
|
||||
|
||||
let av = UIActivityViewController(activityItems: [temporaryURL], applicationActivities: nil)
|
||||
|
||||
let keyWindow = UIApplication.shared.connectedScenes
|
||||
.filter({$0.activationState == .foregroundActive})
|
||||
.map({$0 as? UIWindowScene})
|
||||
.compactMap({$0})
|
||||
.first?.windows
|
||||
.filter({$0.isKeyWindow}).first
|
||||
|
||||
keyWindow?.rootViewController?.present(av, animated: true, completion: nil)
|
||||
} catch {
|
||||
print( "ERROR - \(error)" )
|
||||
}
|
||||
}
|
||||
|
||||
func dgToText( _ dg : DataGroupId ) -> String {
|
||||
switch ( dg ) {
|
||||
case .SOD:
|
||||
return "SOD - Document Security Object"
|
||||
case .COM:
|
||||
return "COM - Header and DG Presence"
|
||||
case .DG1:
|
||||
return "DG1* - MRZ Info"
|
||||
case .DG2:
|
||||
return "DG2* - Face image"
|
||||
case .DG3:
|
||||
return "DG3* - Fingerprints"
|
||||
case .DG4:
|
||||
return "DG4* - Iris"
|
||||
case .DG5:
|
||||
return "DG5* - Displayed portrait"
|
||||
case .DG6:
|
||||
return "DG6 - Reserved"
|
||||
case .DG7:
|
||||
return "DG7* - Signature"
|
||||
case .DG8:
|
||||
return "DG8* - Data features"
|
||||
case .DG9:
|
||||
return "DG9* - Structure features"
|
||||
case .DG10:
|
||||
return "DG10* - Substance features"
|
||||
case .DG11:
|
||||
return "DG11* - Additional personal info"
|
||||
case .DG12:
|
||||
return "DG12* - Additional document info"
|
||||
case .DG13:
|
||||
return "DG13* - Optional details"
|
||||
case .DG14:
|
||||
return "DG14 - Security options"
|
||||
case .DG15:
|
||||
return "DG15 - Active Auth PubKey"
|
||||
case .DG16:
|
||||
return "DG16 - Person(s) to notify"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct ExportPassportView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
settings.passport = NFCPassportModel()
|
||||
|
||||
return NavigationView {
|
||||
ExportPassportView()
|
||||
}
|
||||
.environmentObject(settings)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// CheckBoxView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 10/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CheckBoxButtonStyle: ButtonStyle {
|
||||
|
||||
func makeBody(configuration: Self.Configuration) -> some View {
|
||||
configuration.label
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct CheckBoxView: View {
|
||||
@Binding var checked: Bool
|
||||
var text : String
|
||||
|
||||
var body: some View {
|
||||
HStack() {
|
||||
|
||||
Button(action: {
|
||||
withAnimation {
|
||||
self.checked.toggle()
|
||||
}
|
||||
}) {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
Text(text)
|
||||
Image(systemName:self.checked ? "checkmark.square.fill" : "square")
|
||||
}
|
||||
}
|
||||
.frame(height: 44, alignment: .center)
|
||||
.padding(.trailing)
|
||||
.buttonStyle(CheckBoxButtonStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CheckBoxView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CheckBoxView( checked: .constant(true), text:"Are you on?")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// ViewExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 11/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
extension View {
|
||||
func hideKeyboard() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
func visibility(hidden: Binding<Bool>) -> some View {
|
||||
modifier(VisibilityStyle(hidden: hidden))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ViewModifiers.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 10/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ClearButton: ViewModifier {
|
||||
@Binding var text: String
|
||||
|
||||
public func body(content: Content) -> some View {
|
||||
HStack {
|
||||
content
|
||||
if !text.isEmpty {
|
||||
Button(action: { self.text = "" },
|
||||
label: {
|
||||
Image(systemName: "delete.left")
|
||||
.foregroundColor(Color(UIColor.opaqueSeparator))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VisibilityStyle: ViewModifier {
|
||||
|
||||
@Binding var hidden: Bool
|
||||
func body(content: Content) -> some View {
|
||||
Group {
|
||||
if hidden {
|
||||
content.hidden()
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// MRZEntryView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 10/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// This will be removed once DatePicker inline works correctly
|
||||
struct DateView : View {
|
||||
@Binding var date : Date
|
||||
var title : String
|
||||
|
||||
var body : some View {
|
||||
VStack {
|
||||
Text(title)
|
||||
.font(.largeTitle)
|
||||
Spacer()
|
||||
DatePicker("Date of birth", selection:$date, displayedComponents: .date)
|
||||
.environment(\.timeZone, TimeZone(secondsFromGMT: 0)!)
|
||||
.datePickerStyle(WheelDatePickerStyle())
|
||||
.labelsHidden()
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This should be a nice simple inline DatePicker here
|
||||
// BUT there are bugs when you select dates it changes the date format
|
||||
// from DD MMM YYYY to DD/MM/YYYY!)
|
||||
// Will update when/if this gets fixed!
|
||||
struct MRZEntryView : View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
|
||||
// These will be removed once DatePicker inline works correctly
|
||||
@State private var editDOB = false
|
||||
@State private var editDOE = false
|
||||
@State private var editDateTitle : String = ""
|
||||
|
||||
var body : some View {
|
||||
let passportNrBinding = Binding<String>(get: {
|
||||
settings.passportNumber
|
||||
}, set: {
|
||||
settings.passportNumber = $0.uppercased()
|
||||
})
|
||||
VStack {
|
||||
NavigationLink( destination: DateView(date:$settings.dateOfBirth, title:editDateTitle), isActive: $editDOB) { Text("") }
|
||||
NavigationLink( destination: DateView(date:$settings.dateOfExpiry, title:editDateTitle), isActive: $editDOE) { Text("") }
|
||||
|
||||
TextField("Passport number", text: passportNrBinding)
|
||||
.textCase(.uppercase)
|
||||
.modifier(ClearButton(text: passportNrBinding))
|
||||
.textContentType(.name)
|
||||
.foregroundColor(Color.primary)
|
||||
.padding([.leading, .trailing])
|
||||
.ignoresSafeArea(.keyboard, edges: .all)
|
||||
|
||||
Divider()
|
||||
|
||||
// Replace with DatePicker once it works correctly
|
||||
HStack {
|
||||
VStack {
|
||||
Text( "Date of birth" )
|
||||
Button(formatDate(settings.dateOfBirth)) {
|
||||
editDateTitle = "Select date of birth"
|
||||
editDOB = true
|
||||
}
|
||||
.padding(.horizontal, 15)
|
||||
.padding(.vertical, 8)
|
||||
.background(Color.black.opacity(0.07))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
Spacer()
|
||||
VStack {
|
||||
Text( "Passport expiry date" )
|
||||
Button(formatDate(settings.dateOfExpiry)) {
|
||||
editDateTitle = "Select passport expiry date"
|
||||
editDOE = true
|
||||
}
|
||||
.padding(.horizontal, 15)
|
||||
.padding(.vertical, 8)
|
||||
.background(Color.black.opacity(0.07))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
|
||||
Divider()
|
||||
}
|
||||
.ignoresSafeArea(.keyboard, edges: .bottom)
|
||||
}
|
||||
}
|
||||
|
||||
// This will be removed once DatePicker inline works correctly
|
||||
extension MRZEntryView {
|
||||
|
||||
func formatDate( _ date : Date ) -> String {
|
||||
let df = DateFormatter()
|
||||
df.timeZone = TimeZone.init(secondsFromGMT: 0)
|
||||
df.dateFormat = "dd MMM yyyy"
|
||||
let dateStr = df.string(from:date)
|
||||
return dateStr
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct MRZEntryView_Previews : PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
|
||||
return
|
||||
Group {
|
||||
NavigationView {
|
||||
MRZEntryView()
|
||||
}
|
||||
.environmentObject(settings)
|
||||
.environment( \.colorScheme, .light)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// MRZScannerViewController.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 17/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import QKMRZScanner
|
||||
|
||||
// Wraps the QKMRZScanner component in a simple UIView that allows a scan of the MRZ area from a Passport/ID Card
|
||||
struct MRZScanner: UIViewControllerRepresentable {
|
||||
let completionHandler: (String,Date,Date) -> Void
|
||||
|
||||
func makeUIViewController(context: Context) -> MRZScannerViewController {
|
||||
let vc = MRZScannerViewController()
|
||||
vc.mrzScannerView.delegate = context.coordinator
|
||||
return vc
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: MRZScannerViewController, context: Context) {
|
||||
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
return Coordinator(completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
final class Coordinator: NSObject, QKMRZScannerViewDelegate {
|
||||
let completionHandler: (String,Date,Date) -> Void
|
||||
|
||||
init(completionHandler: @escaping (String,Date,Date) -> Void) {
|
||||
self.completionHandler = completionHandler
|
||||
}
|
||||
|
||||
func mrzScannerView(_ mrzScannerView: QKMRZScannerView, didFind scanResult: QKMRZScanResult) {
|
||||
print(scanResult)
|
||||
if let dob = scanResult.birthdate, let doe = scanResult.expiryDate {
|
||||
completionHandler(scanResult.documentNumber, dob, doe)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: UIViewController implementation
|
||||
class MRZScannerViewController: UIViewController {
|
||||
let mrzScannerView = QKMRZScannerView()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.title = "Scan Passport"
|
||||
self.navigationController?.title = "Scan passport"
|
||||
|
||||
|
||||
let lbl = UILabel()
|
||||
lbl.text = "Please scan the Machine Readable Zone."
|
||||
lbl.numberOfLines = 0
|
||||
self.view.addSubview(mrzScannerView)
|
||||
self.view.addSubview(lbl)
|
||||
|
||||
mrzScannerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
mrzScannerView.topAnchor.constraint(equalTo: view.topAnchor, constant:50).isActive = true
|
||||
mrzScannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
|
||||
mrzScannerView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
|
||||
mrzScannerView.heightAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
|
||||
|
||||
lbl.translatesAutoresizingMaskIntoConstraints = false
|
||||
lbl.leadingAnchor.constraint(equalTo: mrzScannerView.leadingAnchor, constant: 10).isActive = true
|
||||
lbl.topAnchor.constraint(equalTo: mrzScannerView.bottomAnchor, constant: 10).isActive = true
|
||||
lbl.trailingAnchor.constraint(equalTo: mrzScannerView.trailingAnchor, constant: 10).isActive = true
|
||||
}
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
mrzScannerView.startScanning()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
mrzScannerView.stopScanning()
|
||||
}
|
||||
}
|
||||
|
||||
extension MRZScannerViewController : QKMRZScannerViewDelegate {
|
||||
func mrzScannerView(_ mrzScannerView: QKMRZScannerView, didFind scanResult: QKMRZScanResult) {
|
||||
print(scanResult)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// MainView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 04/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import NFCPassportReader
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
|
||||
struct MainView : View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
@State private var showingAlert = false
|
||||
@State private var showingSheet = false
|
||||
@State private var showDetails = false
|
||||
@State private var alertTitle : String = ""
|
||||
@State private var alertMessage : String = ""
|
||||
@State private var showSettings : Bool = false
|
||||
@State private var showScanMRZ : Bool = false
|
||||
@State private var showSavedPassports : Bool = false
|
||||
|
||||
@State var page = 0
|
||||
|
||||
@State var bgColor = Color( UIColor.systemBackground )
|
||||
|
||||
private let passportReader = PassportReader()
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ZStack {
|
||||
NavigationLink( destination: SettingsView(), isActive: $showSettings) { Text("") }
|
||||
NavigationLink( destination: PassportView(), isActive: $showDetails) { Text("") }
|
||||
NavigationLink( destination: StoredPassportView(), isActive: $showSavedPassports) { Text("") }
|
||||
NavigationLink( destination: MRZScanner(completionHandler:{ (nr,dob,doe) in
|
||||
settings.passportNumber = nr
|
||||
settings.dateOfBirth = dob
|
||||
settings.dateOfExpiry = doe
|
||||
showScanMRZ = false
|
||||
}).navigationTitle("Scan MRZ"), isActive: $showScanMRZ){ Text("") }
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Spacer()
|
||||
Button(action: {self.showScanMRZ.toggle()}) {
|
||||
Label("Scan MRZ", systemImage:"camera")
|
||||
}.padding([.top, .trailing])
|
||||
}
|
||||
MRZEntryView()
|
||||
|
||||
Button(action: {
|
||||
self.scanPassport()
|
||||
}) {
|
||||
Text("Scan Passport")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(isValid ? .secondary : Color.secondary.opacity(0.25))
|
||||
}
|
||||
.disabled( !isValid )
|
||||
|
||||
Spacer()
|
||||
HStack(alignment:.firstTextBaseline) {
|
||||
Text( "Version - \(UIApplication.version)" )
|
||||
.font(.footnote)
|
||||
.padding(.leading)
|
||||
Spacer()
|
||||
Button(action: {
|
||||
shareLogs()
|
||||
}) {
|
||||
Text("Share logs")
|
||||
.foregroundColor(.secondary)
|
||||
}.padding(.trailing)
|
||||
.disabled( !isValid )
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitle("Passport details", displayMode: .automatic)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Menu {
|
||||
Button(action: {showSettings.toggle()}) {
|
||||
Label("Settings", systemImage: "gear")
|
||||
}
|
||||
Button(action: {self.showSavedPassports.toggle()}) {
|
||||
Label("Show saved passports", systemImage: "doc")
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "gear")
|
||||
.foregroundColor(Color.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $showingAlert) {
|
||||
Alert(title: Text(alertTitle), message:
|
||||
Text(alertMessage), dismissButton: .default(Text("Got it!")))
|
||||
}
|
||||
.background(colorScheme == .dark ? Color.black : Color.white)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: View functions - functions that affect the view
|
||||
extension MainView {
|
||||
|
||||
var isValid : Bool {
|
||||
return settings.passportNumber.count >= 8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Action Functions
|
||||
extension MainView {
|
||||
|
||||
func shareLogs() {
|
||||
hideKeyboard()
|
||||
PassportUtils.shareLogs()
|
||||
}
|
||||
|
||||
func scanPassport( ) {
|
||||
hideKeyboard()
|
||||
self.showDetails = false
|
||||
|
||||
let df = DateFormatter()
|
||||
df.timeZone = TimeZone(secondsFromGMT: 0)
|
||||
df.dateFormat = "YYMMdd"
|
||||
|
||||
let pptNr = settings.passportNumber
|
||||
let dob = df.string(from:settings.dateOfBirth)
|
||||
let doe = df.string(from:settings.dateOfExpiry)
|
||||
|
||||
let passportUtils = PassportUtils()
|
||||
let mrzKey = passportUtils.getMRZKey( passportNumber: pptNr, dateOfBirth: dob, dateOfExpiry: doe)
|
||||
|
||||
// Set the masterListURL on the Passport Reader to allow auto passport verification
|
||||
let masterListURL = Bundle.main.url(forResource: "masterList", withExtension: ".pem")!
|
||||
passportReader.setMasterListURL( masterListURL )
|
||||
|
||||
// Set whether to use the new Passive Authentication verification method (default true) or the old OpenSSL CMS verifiction
|
||||
passportReader.passiveAuthenticationUsesOpenSSL = !settings.useNewVerificationMethod
|
||||
|
||||
// If we want to read only specific data groups we can using:
|
||||
// let dataGroups : [DataGroupId] = [.COM, .SOD, .DG1, .DG2, .DG7, .DG11, .DG12, .DG14, .DG15]
|
||||
// passportReader.readPassport(mrzKey: mrzKey, tags:dataGroups, completed: { (passport, error) in
|
||||
|
||||
Log.logLevel = settings.logLevel
|
||||
Log.storeLogs = settings.shouldCaptureLogs
|
||||
Log.clearStoredLogs()
|
||||
|
||||
Log.error( "Using version \(UIApplication.version)" )
|
||||
|
||||
Task {
|
||||
let customMessageHandler : (NFCViewDisplayMessage)->String? = { (displayMessage) in
|
||||
switch displayMessage {
|
||||
case .requestPresentPassport:
|
||||
return "Hold your iPhone near an NFC enabled passport."
|
||||
default:
|
||||
// Return nil for all other messages so we use the provided default
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let passport = try await passportReader.readPassport( mrzKey: mrzKey, customDisplayMessage:customMessageHandler)
|
||||
|
||||
if settings.savePassportOnScan {
|
||||
// Save passport
|
||||
let dict = passport.dumpPassportData(selectedDataGroups: DataGroupId.allCases, includeActiveAuthenticationData: true)
|
||||
if let data = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) {
|
||||
|
||||
let savedPath = FileManager.cachesFolder.appendingPathComponent("\(passport.documentNumber).json")
|
||||
|
||||
try? data.write(to: savedPath, options: .completeFileProtection)
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.settings.passport = passport
|
||||
self.showDetails = true
|
||||
}
|
||||
} catch {
|
||||
self.alertTitle = "Oops"
|
||||
self.alertTitle = error.localizedDescription
|
||||
self.showingAlert = true
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: PreviewProvider
|
||||
#if DEBUG
|
||||
struct ContentView_Previews : PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
|
||||
return Group {
|
||||
MainView()
|
||||
.environmentObject(settings)
|
||||
.environment( \.colorScheme, .light)
|
||||
MainView()
|
||||
.environmentObject(settings)
|
||||
.environment( \.colorScheme, .dark)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// PassportSummaryView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 17/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct PassportSummaryView: View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
|
||||
@State var passport: NFCPassportModel
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
PassportDetailsView(passport: passport)
|
||||
.background( Color.primary.colorInvert() )
|
||||
.cornerRadius(10)
|
||||
.shadow(radius: 20)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.stroke(Color.primary, lineWidth: 2)
|
||||
)
|
||||
.padding()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Shows the Pzssport details
|
||||
struct PassportDetailsView : View {
|
||||
var passport: NFCPassportModel
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading) {
|
||||
Image(uiImage:passport.passportImage ?? UIImage(named:"head")!)
|
||||
.resizable()
|
||||
.renderingMode(.original)
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 120, height: 180)
|
||||
.padding([.leading], 10.0)
|
||||
}
|
||||
VStack {
|
||||
HStack {
|
||||
Text( passport.documentType)
|
||||
Text( passport.issuingAuthority)
|
||||
Text( passport.documentNumber)
|
||||
Spacer()
|
||||
}
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text( passport.lastName)
|
||||
Text( passport.firstName)
|
||||
Text( passport.nationality)
|
||||
Text( passport.dateOfBirth)
|
||||
Text( passport.gender)
|
||||
Text( passport.documentExpiryDate )
|
||||
}
|
||||
Spacer()
|
||||
VStack {
|
||||
if !passport.passportDataNotTampered {
|
||||
Image( systemName:"exclamationmark").foregroundColor(.red)
|
||||
.font(.system(size: 20))
|
||||
Text( "Tampered")
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
.padding(.bottom)
|
||||
}
|
||||
if passport.passportCorrectlySigned && passport.documentSigningCertificateVerified {
|
||||
Image( systemName:"checkmark.seal").foregroundColor(.green)
|
||||
.font(.system(size: 25))
|
||||
Text( "Genuine")
|
||||
.font(.caption)
|
||||
.foregroundColor(.green)
|
||||
} else {
|
||||
Image( systemName:"xmark.seal").foregroundColor(.red)
|
||||
.font(.system(size: 25))
|
||||
.padding([.leading,.trailing], 15)
|
||||
Text( "Not Genuine")
|
||||
.font(.caption)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
.padding(.trailing)
|
||||
}
|
||||
}
|
||||
.padding(.top, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PassportSummaryView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
let settings = SettingsStore()
|
||||
let passport = NFCPassportModel()
|
||||
|
||||
return Group {
|
||||
PassportSummaryView(passport:passport)
|
||||
.environment( \.colorScheme, .light)
|
||||
.environmentObject(settings)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
//
|
||||
// PassportView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 30/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct PassportView : View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
@State private var showExportPassport : Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
NavigationLink( destination: ExportPassportView(), isActive: $showExportPassport) { Text("") }
|
||||
|
||||
PassportSummaryView(passport:settings.passport!)
|
||||
HStack {
|
||||
|
||||
Button(action: {showExportPassport.toggle()}) {
|
||||
Label("Export passport", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
.padding()
|
||||
Spacer()
|
||||
Button(action: {shareLogs()}) {
|
||||
Label("Share logs", systemImage: "square.and.arrow.up")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
DetailsView(passport:settings.passport!)
|
||||
}
|
||||
.navigationTitle("Passport Details")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
||||
extension PassportView {
|
||||
func shareLogs() {
|
||||
hideKeyboard()
|
||||
PassportUtils.shareLogs()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct PassportView_Previews : PreviewProvider {
|
||||
static var previews: some View {
|
||||
|
||||
let passport : NFCPassportModel
|
||||
if let file = Bundle.main.url(forResource: "passport", withExtension: "json"),
|
||||
let data = try? Data(contentsOf: file),
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: []),
|
||||
let arr = json as? [String:String] {
|
||||
passport = NFCPassportModel(from: arr)
|
||||
} else {
|
||||
passport = NFCPassportModel()
|
||||
}
|
||||
let settings = SettingsStore()
|
||||
settings.passport = passport
|
||||
|
||||
return NavigationView {
|
||||
PassportView()
|
||||
.environmentObject(settings)
|
||||
.environment( \.colorScheme, .light)
|
||||
.navigationTitle("WEEE")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// SettingsView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 10/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct SettingsView: View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
|
||||
private var logLevels = ["Verbose", "Debug", "Info", "Warning", "Error"]
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(header: Text("Logging settings")) {
|
||||
Toggle(isOn: $settings.shouldCaptureLogs) {
|
||||
Text("Should capture logs")
|
||||
}
|
||||
|
||||
Picker(
|
||||
selection: $settings.logLevel,
|
||||
label: Text("Logging level")
|
||||
) {
|
||||
ForEach(LogLevel.allCases, id: \.self) {
|
||||
Text(logLevels[$0.rawValue] ).tag($0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Section(header: Text("Passport reading settings")) {
|
||||
Toggle(isOn: $settings.useNewVerificationMethod) {
|
||||
Text("Use new Passive Authentication")
|
||||
}
|
||||
.padding(.bottom)
|
||||
VStack {
|
||||
Toggle(isOn: $settings.savePassportOnScan) {
|
||||
Text("Save passport on scan & import")
|
||||
}
|
||||
HStack {
|
||||
Text( "Note - currently stored as JSON on device\nWill not be backed up to iCloud" )
|
||||
.font(.footnote)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.navigationBarTitle(Text("Settings"))
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
SettingsView()
|
||||
.environmentObject(settings)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// StorePassportView.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 17/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import NFCPassportReader
|
||||
|
||||
struct StoredPassportView: View {
|
||||
@EnvironmentObject var settings: SettingsStore
|
||||
@State private var showImport : Bool = false
|
||||
@State private var showDetails = false
|
||||
@State private var storedPassports = [URL]()
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
NavigationLink( destination: PassportView(), isActive: $showDetails) { Text("") }
|
||||
|
||||
VStack {
|
||||
List {
|
||||
ForEach(self.storedPassports, id: \.self) { item in
|
||||
Button(action:{
|
||||
if let data = try? Data(contentsOf: item),
|
||||
let passport = loadPassport(data:data) {
|
||||
self.settings.passport = passport
|
||||
self.showDetails = true
|
||||
}
|
||||
}) {
|
||||
HStack {
|
||||
Text(item.deletingPathExtension().lastPathComponent)
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.onDelete(perform: deletePassport)
|
||||
}
|
||||
Spacer()
|
||||
if ( !settings.savePassportOnScan ) {
|
||||
Text( "Imported or scanned passports are currently not being saved.\nThis can be changed in Settings" )
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Menu {
|
||||
Button(action: {self.showImport.toggle()}) {
|
||||
Label("Import passport", systemImage: "doc")
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "square.and.arrow.down")
|
||||
.foregroundColor(Color.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.fileImporter(
|
||||
isPresented: $showImport, allowedContentTypes: [.json,.text],
|
||||
allowsMultipleSelection: false
|
||||
) { result in
|
||||
|
||||
hideKeyboard()
|
||||
|
||||
guard let selectedFile: URL = try? result.get().first else { return }
|
||||
if selectedFile.startAccessingSecurityScopedResource() {
|
||||
defer { selectedFile.stopAccessingSecurityScopedResource() }
|
||||
importFile( url:selectedFile )
|
||||
} else {
|
||||
print("Unable to read file contents - denied")
|
||||
}
|
||||
|
||||
}
|
||||
.onAppear() {
|
||||
loadStoredPassports()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension StoredPassportView {
|
||||
func loadStoredPassports() {
|
||||
|
||||
do {
|
||||
let urls = try FileManager.default.contentsOfDirectory(at: FileManager.cachesFolder, includingPropertiesForKeys: nil, options: [])
|
||||
|
||||
storedPassports = urls.filter { $0.pathExtension == "json" }
|
||||
} catch {
|
||||
print("Could not search for urls of files in documents directory: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func importFile( url : URL ) {
|
||||
Log.logLevel = settings.logLevel
|
||||
Log.storeLogs = settings.shouldCaptureLogs
|
||||
Log.clearStoredLogs()
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: url )
|
||||
if let passport = loadPassport( data: data ) {
|
||||
|
||||
if ( settings.savePassportOnScan ) {
|
||||
// Save passport to docs folder
|
||||
let savedPath = FileManager.cachesFolder.appendingPathComponent("\(passport.documentNumber).json")
|
||||
try? data.write(to: savedPath, options: .completeFileProtection)
|
||||
}
|
||||
|
||||
self.settings.passport = passport
|
||||
self.showDetails = true
|
||||
}
|
||||
} catch {
|
||||
// Handle failure.
|
||||
print("Unable to read file contents")
|
||||
print(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func loadPassport( data: Data) -> NFCPassportModel? {
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: [])
|
||||
if let arr = json as? [String:String] {
|
||||
|
||||
let passport = NFCPassportModel(from: arr)
|
||||
|
||||
let masterListURL = Bundle.main.url(forResource: "masterList", withExtension: ".pem")!
|
||||
passport.verifyPassport(masterListURL: masterListURL)
|
||||
return passport
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deletePassport( at offsets: IndexSet) {
|
||||
|
||||
let fm = FileManager.default
|
||||
offsets.forEach {
|
||||
let url = storedPassports[$0]
|
||||
try? fm.removeItem(at: url)
|
||||
}
|
||||
storedPassports.remove(atOffsets: offsets)
|
||||
}
|
||||
}
|
||||
|
||||
struct StoredPassportView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let settings = SettingsStore()
|
||||
|
||||
StoredPassportView()
|
||||
.environmentObject(settings)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCA1wCCQDFcc+Un66UsDANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJH
|
||||
QjESMBAGA1UECAwJU29tZXdoZXJlMRIwEAYDVQQHDAlUaGlzIENpdHkxCzAJBgNV
|
||||
BAoMAk5BMQswCQYDVQQLDAJOQTENMAsGA1UEAwwEdGVzdDEcMBoGCSqGSIb3DQEJ
|
||||
ARYNdGVzdEB0ZXN0LmNvbTAeFw0xOTA2MjgxMzAyNTlaFw0yMDA2MjcxMzAyNTla
|
||||
MHwxCzAJBgNVBAYTAkdCMRIwEAYDVQQIDAlTb21ld2hlcmUxEjAQBgNVBAcMCVRo
|
||||
aXMgQ2l0eTELMAkGA1UECgwCTkExCzAJBgNVBAsMAk5BMQ0wCwYDVQQDDAR0ZXN0
|
||||
MRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3QuY29tMIICIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAg8AMIICCgKCAgEA4sTb0Xd20ATso1VffMGK/N2TuEcsZvQkbhr75dd6f77y
|
||||
3h5r5ikFCcppGwlgEy6/wn0iEiv4iGDm7cxvVSfwZ+Bm7nbYZVHl8G7vYUZRdLnh
|
||||
tcUpfa+jPyrQ+XXfTygjoE2shAs8Wv+uB/O0oLbltdx5HMcitHj6MkIz3bs6hY4Z
|
||||
2kSy6JB1Iw0GwB6vfHbD8MUkn0Aqxwdrd5ks61lVpYx3JyvhUXVjC/9rE+dk6+cN
|
||||
16WvRhCEH6aClgWcfkSfDtZ85ltcyL3glAqX1YMLl4CFRKZ3NLVgXjHj/QYvAXJq
|
||||
yWoNbAQvCFv5WK8/JjtAzFYKwjGGUhG5tL6etLrfDF/RudrLDIS2Js9cTMbbB10O
|
||||
UehVksJvYQBaj8VRSsI7GrGydecfBixwqYD5DxcPzZsGcsfzuQYkotG+poDhjRE4
|
||||
Ow9zqIG20hgnBn3VTbP21yc4woYLzIK7M7MdWDiDqqcrLwtxolIk6R6lc/3wVR8i
|
||||
19F5HFwKM0RW3cWZhXqCHrpYBzj8gx7hJAKSFZWDygLFH8h1LtMx93kstxPR7FA6
|
||||
99737YU1HF0j7kjKJAIQqoJ43ftUN9q8sDN/rRpEgKnRUuFrvcaTdTZCJ7NT3u6p
|
||||
edC+8rdbKQO6TX0JC8PEl1FjTiVnb3wpMpWPYaI3hspSN/CMUunypoKRJ5IgSK8C
|
||||
AwEAATANBgkqhkiG9w0BAQsFAAOCAgEAJtrliSVzukKjUJR3AnZrgcnWZ8kTGH9E
|
||||
TSfpmc9IkMvwWvBs/vgpKMm3XVzTM1RcI/pQYR9Y4beXf4wgTQIg1I2kWLVcRMzU
|
||||
rwFWl2/h6uA6G+tJpaVVy30rPcYGqLmBqzCCRb3sf/H77/6nknafA4jMASlIWnTE
|
||||
R7HBd0cJa50jaTgFaIe734oIMqaAZvFFKK5KDnxSBMHwUf7ej1ibT/rB5Ry80qpJ
|
||||
FsKlxpjaeUDWsnnjR4Z98rjDsWOSI8tUTStdnPYTw/6VFsf+zPKwE2u2Qe7SXg3S
|
||||
eUoCQqWYaSMqmAfTVJx7zIDIvxa8+LmtijeqYUZcfnos0xxTEeJ6EH65rAPOi23x
|
||||
1pg8Z28NAAinqFAo74Hr2hTKESmq0mykF/XP4wLhhaxYHy+FFwm984IIpqbKJmuY
|
||||
/LapNMi6hZXRXft5PQYe57ZXD9/Lp8pn+19nX0nyv5agius0/R4M3CvuPbdose64
|
||||
jm+2325MQAhihrHmcU0YIt1kwSMuiYOqwD5plx+yenCIhdR6Oa5WX7Xf/hiKZult
|
||||
5UVNVxfG1tZbsk/u2iwd2fDMBGQ3/D36REA5el6GUPpBOaa6gVmpS38qRCTVTBqH
|
||||
NY8Qy6N+AHsahMtMakwo/EWsDsGTajcrvXX1psLgpRdMNeXgU3nNzJ+wPMUPCTFB
|
||||
ZhNynFjgmgY=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,10 @@
|
||||
# NFCPassportReaderApp
|
||||
|
||||
This is a sample app showing how to read a e-passport using the NFCPassportReader library
|
||||
|
||||
|
||||
This is purely a demonstration - you have to manually enter the passport number, the date of birth and passport expiry date but it does calculate the checksums for you.
|
||||
|
||||
Also, the last entered passport details are saved to UserDefaults to save you having to re-enter them each time.
|
||||
|
||||
It reads my passport (and others I've been able to test) fine, however your milage may vary.
|
||||
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// DataGroupParsingTests.swift
|
||||
//
|
||||
//
|
||||
// Created by Andy Qua on 15/06/2019.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
import OpenSSL
|
||||
|
||||
@testable import NFCPassportReader
|
||||
|
||||
|
||||
final class DataGroupParsingTests: XCTestCase {
|
||||
func testDatagroup1Parsing() {
|
||||
|
||||
// Random generated test MRZ
|
||||
let mrz = "P<GBRTHATCHER<<BOB<<<<<<<<<<<<<<<<<<<<<<<<<<7125143269GBR3906022M1601013<<<<<<<<<<<<<<08"
|
||||
let mrzBin = [UInt8](mrz.data(using: .utf8)!)
|
||||
let tag = try! [0x5F,0x1F] + toAsn1Length(mrzBin.count) + mrzBin
|
||||
let dg1 = try! [0x61] + toAsn1Length(tag.count) + tag
|
||||
|
||||
let dgp = DataGroupParser()
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg1)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup1 )
|
||||
}
|
||||
}
|
||||
|
||||
func testDatagroup2ParsingJPEG2000() {
|
||||
|
||||
// This is a cut down version of the DG2 record. It contains everything up to the end of the image header - no actuall image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg2 = hexRepToBin("75617F61570201017F6082203FA1128002010081010282010087020101880200085F2E38464143003031300000002026000100002018000000000000000000010000000000000001000000000000000000000000000C6A5020200D0A")
|
||||
|
||||
let dgp = DataGroupParser()
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg2)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup2 )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testDatagroup2ParsingJPEG() {
|
||||
|
||||
// This is a cut down version of the DG2 record. It contains everything up to the begininnig of what would be the image data - no actual image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg2 = hexRepToBin("75617F618220470201017F6082203FA1128002010081010282010087020101880200085F2E3846414300303130000000202600010000201800000000000000000001000000000000000100000000000000000000FFD8FFE000104A464946")
|
||||
let dgp = DataGroupParser()
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg2)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup2 )
|
||||
}
|
||||
}
|
||||
|
||||
func testDatagroup7ParsingJPEG() {
|
||||
|
||||
// This is a cut down version of the DG7 record. It contains everything up to the end of the image header - no actuall image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg7 = hexRepToBin("678220060201015F4300")
|
||||
let dgp = DataGroupParser()
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg7)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup7 )
|
||||
}
|
||||
}
|
||||
|
||||
func testDatagroup11Parsing() {
|
||||
|
||||
// This is a cut down version of the DG7 record. It contains everything up to the end of the image header - no actuall image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg11Val = hexRepToBin("6B305C065F0E5F2B5F115F0E0C546573743C3C5465737465725F2B0831393730313230315F110B4E6F727468616D70746F6E")
|
||||
let dgp = DataGroupParser()
|
||||
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg11Val)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup11 )
|
||||
|
||||
let dg11 = dg as! DataGroup11
|
||||
XCTAssertEqual(dg11.fullName, "Test<<Tester")
|
||||
XCTAssertEqual(dg11.dateOfBirth, "19701201")
|
||||
XCTAssertEqual(dg11.placeOfBirth, "Northampton")
|
||||
}
|
||||
}
|
||||
|
||||
func testDatagroup12Parsing() {
|
||||
|
||||
// This is a cut down version of the DG7 record. It contains everything up to the end of the image header - no actuall image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg12Val = hexRepToBin("6C1A5C045F265F195F260832303138303332365F1906544553544552")
|
||||
let dgp = DataGroupParser()
|
||||
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg12Val)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup12 )
|
||||
|
||||
let dg12 = dg as! DataGroup12
|
||||
XCTAssertEqual(dg12.issuingAuthority, "TESTER")
|
||||
XCTAssertEqual(dg12.dateOfIssue, "20180326")
|
||||
}
|
||||
}
|
||||
|
||||
func testDatagroup15Parsing() {
|
||||
|
||||
// This is a cut down version of the DG7 record. It contains everything up to the end of the image header - no actuall image data as its way too big to include here
|
||||
// I've also adjusted the record lengths accordingly
|
||||
|
||||
let dg15Val = hexRepToBin("6F820137308201333081EC06072A8648CE3D02013081E0020101302C06072A8648CE3D0101022100A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377304404207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9042026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B60441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997022100A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7020101034200049BD24313046EB43CC4652B6FC1AA00E76B5405F4E7016521E95BE53B9C5BAE5A1410F12CF3AE23F886EFCEDE89F7C63AD9CA9E5C6C05DE902DB70F2EB2341F9D")
|
||||
let dgp = DataGroupParser()
|
||||
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: dg15Val)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is DataGroup15 )
|
||||
|
||||
let dg15 = dg as? DataGroup15
|
||||
XCTAssertTrue( dg15?.ecdsaPublicKey != nil || dg15?.rsaPublicKey != nil )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testCOMDatagroupParsing() {
|
||||
let com = hexRepToBin("601A5F0104303130375F36063034303030305C08617563676B6C6E6F")
|
||||
let dgp = DataGroupParser()
|
||||
XCTAssertNoThrow(try dgp.parseDG(data: com)) { dg in
|
||||
XCTAssertNotNil(dg)
|
||||
XCTAssertTrue( dg is COM )
|
||||
guard let com = dg as? COM else { XCTFail(); return }
|
||||
|
||||
// Version should be 0x30313037 or [0x30, 0x31, 0x30, 0x37]
|
||||
XCTAssertEqual( com.version, "1.7")
|
||||
|
||||
// Unicode version should be 0x303430303030 or [0x30, 0x34, 0x30, 0x30, 0x30, 0x30]
|
||||
XCTAssertEqual( com.unicodeVersion, "4.0.0")
|
||||
|
||||
// Datagroups present are COM, DG1, DG2, DG3, DG7, DG11, DG12, DG14, DG15
|
||||
XCTAssertEqual( com.dataGroupsPresent,["DG1", "DG2", "DG3", "DG7", "DG11", "DG12", "DG14", "DG15"])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testDatagroup1Parsing", testDatagroup1Parsing),
|
||||
("testDatagroup2Parsing", testDatagroup2ParsingJPEG2000),
|
||||
("testDatagroup2ParsingJPEG", testDatagroup2ParsingJPEG),
|
||||
("testCOMDatagroupParsing", testCOMDatagroupParsing),
|
||||
]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,260 @@
|
||||
import XCTest
|
||||
import CoreNFC
|
||||
import OpenSSL
|
||||
|
||||
@testable import NFCPassportReader
|
||||
|
||||
public func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: String = "", file: StaticString = #file, line: UInt = #line, also validateResult: (T) -> Void) {
|
||||
func executeAndAssignResult(_ expression: @autoclosure () throws -> T, to: inout T?) rethrows {
|
||||
to = try expression()
|
||||
}
|
||||
var result: T?
|
||||
XCTAssertNoThrow(try executeAndAssignResult(expression(), to: &result), message, file: file, line: line)
|
||||
if let r = result {
|
||||
validateResult(r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class NFCPassportReaderTests: XCTestCase {
|
||||
|
||||
func testBinToHexRep() {
|
||||
let val : [UInt8] = [0x12, 0x24, 0x55, 0x77]
|
||||
XCTAssertEqual( binToHexRep(val), "12245577" )
|
||||
}
|
||||
|
||||
func testHexRepToBin() {
|
||||
let val : [UInt8] = [0x12, 0x24, 0x55, 0x77]
|
||||
XCTAssertEqual( hexRepToBin("12245577"), val )
|
||||
}
|
||||
|
||||
func testAsn1Length() {
|
||||
// Test < 127
|
||||
XCTAssertNoThrow(try asn1Length([0x32])) { (len, offset) in
|
||||
XCTAssertEqual(len, 0x32)
|
||||
XCTAssertEqual(offset, 1)
|
||||
}
|
||||
|
||||
// Test 127
|
||||
XCTAssertNoThrow(try asn1Length([0x7f])) { (len, offset) in
|
||||
XCTAssertEqual(len, 0x7f)
|
||||
XCTAssertEqual(offset, 1)
|
||||
}
|
||||
|
||||
// Test 128
|
||||
XCTAssertNoThrow(try asn1Length([0x81, 0x80])) { (len, offset) in
|
||||
XCTAssertEqual(len, 128)
|
||||
XCTAssertEqual(offset, 2)
|
||||
}
|
||||
|
||||
// Test 255
|
||||
XCTAssertNoThrow(try asn1Length([0x81, 0xFF])) { (len, offset) in
|
||||
XCTAssertEqual(len, 255)
|
||||
XCTAssertEqual(offset, 2)
|
||||
}
|
||||
|
||||
// Test 256
|
||||
XCTAssertNoThrow(try asn1Length([0x82, 0x01,0x00])) { (len, offset) in
|
||||
XCTAssertEqual(len, 256)
|
||||
XCTAssertEqual(offset, 3)
|
||||
}
|
||||
|
||||
// Test 1000
|
||||
XCTAssertNoThrow(try asn1Length([0x82, 0x03, 0xE8])) { (len, offset) in
|
||||
XCTAssertEqual(len, 1000)
|
||||
XCTAssertEqual(offset, 3)
|
||||
}
|
||||
|
||||
// Test Max value - 65535
|
||||
XCTAssertNoThrow(try asn1Length([0x82, 0xff, 0xff])) { (len, offset) in
|
||||
XCTAssertEqual(len, 65535)
|
||||
XCTAssertEqual(offset, 3)
|
||||
}
|
||||
|
||||
// Test Too Big
|
||||
XCTAssertThrowsError(try toAsn1Length(65536))
|
||||
}
|
||||
|
||||
func testToASNLength() {
|
||||
// Test < 127
|
||||
XCTAssertNoThrow(try toAsn1Length(50)) { data in
|
||||
XCTAssertEqual(data.count, 1)
|
||||
XCTAssertEqual(data[0], 0x32)
|
||||
}
|
||||
|
||||
// Test 127
|
||||
XCTAssertNoThrow(try toAsn1Length(127)) { data in
|
||||
XCTAssertEqual(data.count, 1)
|
||||
XCTAssertEqual(data[0], 0x7f)
|
||||
}
|
||||
|
||||
// Test 128
|
||||
XCTAssertNoThrow(try toAsn1Length(128)) { data in
|
||||
XCTAssertEqual(data.count, 2)
|
||||
XCTAssertEqual(data[0], 0x81)
|
||||
XCTAssertEqual(data[1], 0x80)
|
||||
}
|
||||
|
||||
// Test 255
|
||||
XCTAssertNoThrow(try toAsn1Length(255)) { data in
|
||||
XCTAssertEqual(data.count, 2)
|
||||
XCTAssertEqual(data[0], 0x81)
|
||||
XCTAssertEqual(data[1], 0xff)
|
||||
}
|
||||
|
||||
// Test 256
|
||||
XCTAssertNoThrow(try toAsn1Length(256)) { data in
|
||||
XCTAssertEqual(data.count, 3)
|
||||
XCTAssertEqual(data[0], 0x82)
|
||||
XCTAssertEqual(data[1], 0x01)
|
||||
XCTAssertEqual(data[2], 0x00)
|
||||
}
|
||||
|
||||
// Test 1000
|
||||
XCTAssertNoThrow(try toAsn1Length(1000)) { data in
|
||||
XCTAssertEqual(data.count, 3)
|
||||
XCTAssertEqual(data[0], 0x82)
|
||||
XCTAssertEqual(data[1], 0x03)
|
||||
XCTAssertEqual(data[2], 0xE8)
|
||||
}
|
||||
|
||||
// Test Max value - 65535
|
||||
XCTAssertNoThrow(try toAsn1Length(65535)) { data in
|
||||
XCTAssertEqual(data.count, 3)
|
||||
XCTAssertEqual(data[0], 0x82)
|
||||
XCTAssertEqual(data[1], 0xff)
|
||||
XCTAssertEqual(data[2], 0xff)
|
||||
}
|
||||
|
||||
// Test Too Big
|
||||
XCTAssertThrowsError(try toAsn1Length(65536))
|
||||
}
|
||||
|
||||
|
||||
func testDES3Encryption() {
|
||||
let msg = [UInt8]("maryhadalittlelambaaaaaa".data(using: .utf8)!)
|
||||
let iv : [UInt8] = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let key : [UInt8] = [191, 73, 56, 112, 158, 148, 146, 127, 157, 76, 117, 8, 239, 128, 87, 42]
|
||||
let enc = tripleDESEncrypt(key: key, message: msg, iv: iv)
|
||||
Log.debug("KEY: \(binToHexRep(key))")
|
||||
Log.debug("MSG: \(binToHexRep(msg))")
|
||||
Log.debug("ENC: \(binToHexRep(enc))")
|
||||
|
||||
XCTAssertEqual( binToHexRep(enc), "4DAF068AB358BC9E8F5E916D3DEDE750D92315370E44D9B3" )
|
||||
}
|
||||
|
||||
func testDES3Decryption() {
|
||||
let enc = hexRepToBin("4DAF068AB358BC9E8F5E916D3DEDE750D92315370E44D9B3")
|
||||
let iv : [UInt8] = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
let key : [UInt8] = [191, 73, 56, 112, 158, 148, 146, 127, 157, 76, 117, 8, 239, 128, 87, 42]
|
||||
let dec = tripleDESDecrypt(key: key, message: enc, iv: iv)
|
||||
Log.debug("KEY: \(binToHexRep(key))")
|
||||
Log.debug("ENC: \(binToHexRep(enc))")
|
||||
Log.debug("DEC: \(binToHexRep(dec))")
|
||||
|
||||
let val = String(data:Data(dec), encoding:.utf8)
|
||||
XCTAssertEqual( val, "maryhadalittlelambaaaaaa" )
|
||||
}
|
||||
|
||||
func testSecureMessagingProtect() {
|
||||
|
||||
let KSenc = hexRepToBin("8FDCFE759E40A4DF4575160B3BFB79FB")
|
||||
let KSmac = hexRepToBin("2AE92531E55707D9C4CEF8C2D6E5AD70")
|
||||
let ssc = hexRepToBin("73061884A0E57AA7")
|
||||
|
||||
let sm = SecureMessaging(ksenc: KSenc, ksmac: KSmac, ssc: ssc)
|
||||
|
||||
let data : [UInt8] = [0x00, 0xA4, 0x02, 0x0C, 0x02, 0x01, 0x01, 0x00]
|
||||
let apdu = NFCISO7816APDU(data:Data(data))!
|
||||
let protApdu = try! sm.protect( apdu: apdu )
|
||||
|
||||
XCTAssertNotNil(protApdu.data )
|
||||
XCTAssertEqual( protApdu.instructionClass, 0x0c )
|
||||
XCTAssertEqual( protApdu.instructionCode, 0xA4 )
|
||||
XCTAssertEqual( protApdu.p1Parameter, 0x02 )
|
||||
XCTAssertEqual( protApdu.p2Parameter, 0x0c )
|
||||
|
||||
let hexDataRep = binToHexRep( [UInt8](protApdu.data!))
|
||||
XCTAssertEqual( hexDataRep, "870901CC69089F8F1AB4698E08B6334B3ABD5A9E09" )
|
||||
XCTAssertEqual( protApdu.expectedResponseLength, 0 )
|
||||
}
|
||||
|
||||
func testSecureMessagingUnprotectNoData() {
|
||||
|
||||
// Note - same keys as above but SSC incremented by 1 as per spec
|
||||
let KSenc = hexRepToBin("8FDCFE759E40A4DF4575160B3BFB79FB")
|
||||
let KSmac = hexRepToBin("2AE92531E55707D9C4CEF8C2D6E5AD70")
|
||||
let ssc = hexRepToBin("73061884A0E57AA8")
|
||||
|
||||
let sm = SecureMessaging(ksenc: KSenc, ksmac: KSmac, ssc: ssc)
|
||||
|
||||
let data : [UInt8] = hexRepToBin("990290008E08C61E440E5DD415469000")
|
||||
let protRespApdu = ResponseAPDU(data: data, sw1: 0x90, sw2: 0x00)
|
||||
|
||||
XCTAssertNoThrow(try sm.unprotect( rapdu: protRespApdu )) { rapdu in
|
||||
XCTAssertEqual(binToHexRep(rapdu.data), "")
|
||||
XCTAssertEqual( rapdu.sw1, 0x90 )
|
||||
XCTAssertEqual( rapdu.sw2, 0x00 )
|
||||
}
|
||||
}
|
||||
|
||||
func testSecureMessagingUnprotectWithData() {
|
||||
|
||||
let KSenc = hexRepToBin("8FDCFE759E40A4DF4575160B3BFB79FB")
|
||||
let KSmac = hexRepToBin("2AE92531E55707D9C4CEF8C2D6E5AD70")
|
||||
let ssc = hexRepToBin("73061884A0E57AAA")
|
||||
|
||||
let sm = SecureMessaging(ksenc: KSenc, ksmac: KSmac, ssc: ssc)
|
||||
|
||||
let data : [UInt8] = hexRepToBin("87090156D0EFCC887F8973990290008E08D6B9C0DA21DC965F9000")
|
||||
let protRespApdu = ResponseAPDU(data: data, sw1: 0x90, sw2: 0x00)
|
||||
|
||||
XCTAssertNoThrow(try sm.unprotect( rapdu: protRespApdu )) { rapdu in
|
||||
XCTAssertEqual(binToHexRep(rapdu.data), "615B5F1F")
|
||||
XCTAssertEqual( rapdu.sw1, 0x90 )
|
||||
XCTAssertEqual( rapdu.sw2, 0x00 )
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testConvertECDSAPlainTODer() {
|
||||
let sigText = "67e147aac644325792dfa0b1615956dc4ed54e8cd859341571db98003431936e0651e9a3cdbcea3c8accd75a6f6bf07eb6bcf9ad1728e21aa854049e634e6fbf"
|
||||
let sig = hexRepToBin(sigText)
|
||||
|
||||
let ecsig = ECDSA_SIG_new()
|
||||
defer { ECDSA_SIG_free(ecsig) }
|
||||
sig.withUnsafeBufferPointer { (unsafeBufPtr) in
|
||||
let unsafePointer = unsafeBufPtr.baseAddress!
|
||||
let r = BN_bin2bn(unsafePointer, 32, nil)
|
||||
let s = BN_bin2bn(unsafePointer + 32, 32, nil)
|
||||
ECDSA_SIG_set0(ecsig, r, s)
|
||||
}
|
||||
|
||||
//print( "Sig - \(ecsig)" )
|
||||
|
||||
var derEncodedSignature: UnsafeMutablePointer<UInt8>? = nil
|
||||
let derLength = i2d_ECDSA_SIG(ecsig, &derEncodedSignature)
|
||||
|
||||
var derBytes = [UInt8](repeating: 0, count: Int(derLength))
|
||||
for b in 0..<Int(derLength) {
|
||||
derBytes[b] = derEncodedSignature![b]
|
||||
}
|
||||
|
||||
XCTAssertNoThrow(try OpenSSLUtils.ASN1Parse(data: Data(derBytes)), "Successfully parsed" )
|
||||
|
||||
}
|
||||
|
||||
|
||||
static var allTests = [
|
||||
("testBinToHexRep", testBinToHexRep),
|
||||
("testHexRepToBin", testHexRepToBin),
|
||||
("testAsn1Length", testAsn1Length),
|
||||
("testToASNLength", testToASNLength),
|
||||
("testDES3Encryption", testDES3Encryption),
|
||||
("testDES3Decryption", testDES3Decryption),
|
||||
("testSecureMessagingProtect", testSecureMessagingProtect),
|
||||
("testSecureMessagingUnprotectNoData", testSecureMessagingUnprotectNoData),
|
||||
("testSecureMessagingUnprotectWithData", testSecureMessagingUnprotectWithData),
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// PACETests.swift
|
||||
// NFCPassportReaderAppTests
|
||||
//
|
||||
// Created by Andy Qua on 09/03/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import OpenSSL
|
||||
import NFCPassportReader
|
||||
|
||||
// Currently not actual tests - maybe at some point but currently just a holding place for some testing stuff I didn't want to get rid of!
|
||||
// Hopefully will re-organise into proper tests!
|
||||
class PACETests {
|
||||
func testDHKeyMapping() -> OpaquePointer {
|
||||
var resp : [UInt8] = [0x7c, 0x82, 0x01, 0x04, 0x82, 0x82, 0x01, 0x00, 0x70, 0x5a, 0xce, 0x59, 0x1c, 0x0b, 0xe1, 0xa1, 0x19, 0x5b, 0x14, 0x1c, 0x97, 0x38, 0x51, 0xde, 0x07, 0xf1, 0x66, 0xa6, 0x74, 0x7d, 0x18, 0x9f, 0x5e, 0x3b, 0x51, 0x0d, 0xbf, 0xff, 0xe2, 0x16, 0xca, 0x96, 0x0e, 0x63, 0x8d, 0x16, 0x49, 0x5f, 0x53, 0x15, 0x60, 0x9b, 0xd6, 0x6e, 0x41, 0x52, 0x69, 0x08, 0x6a, 0x37, 0x6f, 0xf4, 0xd6, 0x14, 0xcc, 0x9b, 0x9d, 0x57, 0x0e, 0x64, 0x53, 0x49, 0xa3, 0xe6, 0xd6, 0xdb, 0x80, 0xfb, 0x08, 0x39, 0xb7, 0x66, 0xdc, 0xcc, 0xb1, 0xda, 0xe0, 0xe5, 0x21, 0xaf, 0xca, 0x9b, 0xdc, 0xe2, 0xc2, 0xd9, 0xb2, 0x58, 0xd8, 0x22, 0x94, 0x23, 0x76, 0x0f, 0x40, 0x74, 0xea, 0x73, 0xf1, 0xa4, 0x4d, 0xdd, 0xfc, 0x72, 0x27, 0xda, 0x8b, 0xce, 0x03, 0x75, 0x98, 0xfe, 0x38, 0x81, 0x1d, 0x45, 0xc9, 0xd6, 0x8b, 0x81, 0x8d, 0xef, 0xdc, 0xda, 0x5f, 0xc8, 0x1a, 0x12, 0x51, 0x0d, 0xfa, 0x02, 0x67, 0xf9, 0x89, 0x5e, 0x6d, 0xb8, 0x55, 0x43, 0xb0, 0x71, 0x47, 0x0d, 0xf0, 0x27, 0xda, 0x62, 0x3b, 0xd4, 0xa9, 0x4d, 0x5e, 0xde, 0xba, 0x81, 0x7b, 0xde, 0x79, 0x5f, 0x57, 0xbf, 0x0b, 0x35, 0xf4, 0x29, 0x6f, 0x5a, 0xd4, 0xe8, 0xd9, 0xfd, 0x2c, 0x87, 0x2e, 0x84, 0x26, 0x10, 0x9d, 0x1b, 0x50, 0xe4, 0x1d, 0xb3, 0x91, 0x02, 0xac, 0xa4, 0x58, 0x52, 0x61, 0x77, 0x1f, 0x97, 0x02, 0xd6, 0x48, 0x90, 0x1f, 0x69, 0xb6, 0xa0, 0x53, 0x53, 0xf9, 0xcb, 0x57, 0x01, 0xfe, 0x9f, 0xf2, 0xa1, 0x29, 0x60, 0x3f, 0xa5, 0xa4, 0xf6, 0x3d, 0xf1, 0xc6, 0x7a, 0xf3, 0xc6, 0xfd, 0x11, 0x6c, 0x38, 0xe8, 0x91, 0x82, 0x3c, 0xd9, 0x33, 0xef, 0x57, 0x9e, 0x6c, 0x04, 0x10, 0x65, 0x6a, 0xc5, 0xaa, 0x1f, 0xc4, 0x50, 0x1d, 0xe6, 0xbd, 0x27, 0xe0, 0x79, 0x30, ]
|
||||
|
||||
let mappingKey : OpaquePointer = EVP_PKEY_new()
|
||||
let dhKey = DH_get_2048_256()
|
||||
|
||||
let rc = DH_generate_key(dhKey)
|
||||
EVP_PKEY_set1_DH(mappingKey, dhKey)
|
||||
|
||||
let pubKeyData = try! unwrapDO( tag:0x7c, wrappedData:resp)
|
||||
let encodedPublicKey = try! unwrapDO(tag: 0x82, wrappedData: pubKeyData)
|
||||
|
||||
let piccMappingPublicKey = OpenSSLUtils.decodePublicKeyFromBytes(pubKeyData: encodedPublicKey, params: mappingKey)!
|
||||
let asecret = OpenSSLUtils.computeSharedSecret(privateKeyPair: mappingKey, publicKey: piccMappingPublicKey)
|
||||
|
||||
|
||||
let dh_mapping_key = EVP_PKEY_get1_DH(mappingKey)
|
||||
|
||||
|
||||
print( "DONE" )
|
||||
|
||||
let piccNonce : [UInt8] = [0xed, 0xb6, 0xc4, 0x07, 0x04, 0xae, 0x98, 0xfd,]
|
||||
let bn_nonce = BN_bin2bn(piccNonce, Int32(piccNonce.count), nil);
|
||||
|
||||
let bn = BN_bin2bn(encodedPublicKey, Int32(encodedPublicKey.count), nil);
|
||||
var secret = [UInt8](repeating: 0, count: Int(DH_size(dh_mapping_key)))
|
||||
DH_compute_key( &secret, bn, dh_mapping_key)
|
||||
|
||||
|
||||
let bn_h = BN_bin2bn(secret, Int32(secret.count), nil);
|
||||
|
||||
var p : OpaquePointer? = nil
|
||||
var q : OpaquePointer? = nil
|
||||
var g : OpaquePointer? = nil
|
||||
DH_get0_pqg(dh_mapping_key, &p, &q, &g);
|
||||
|
||||
// map to new generator#imageLiteral(resourceName: "simulator_screenshot_33B42CB4-EA6E-47B4-A2A2-D96CA95B0F15.png")
|
||||
let bn_g = BN_new()
|
||||
let new_g = BN_new()
|
||||
|
||||
// bn_g = g^nonce mod p
|
||||
// ephemeral_key->g = bn_g mod p * h => (g^nonce mod p) * h mod p
|
||||
let bn_ctx = BN_CTX_new()
|
||||
let rc3 = BN_mod_exp(bn_g, g, bn_nonce, p, bn_ctx)
|
||||
let rc4 = BN_mod_mul(new_g, bn_g, bn_h, p, bn_ctx)
|
||||
|
||||
|
||||
let ephemeral_key = DHparams_dup(dh_mapping_key)
|
||||
let rc5 = DH_set0_pqg(ephemeral_key, BN_dup(p), BN_dup(q), BN_dup(new_g))
|
||||
|
||||
BN_free( bn_nonce )
|
||||
BN_free( bn )
|
||||
BN_free(bn_h)
|
||||
BN_free(bn_g)
|
||||
BN_free(new_g)
|
||||
BN_CTX_free(bn_ctx)
|
||||
|
||||
// Set the ephemeral params
|
||||
let ephemeralParams = EVP_PKEY_new()
|
||||
let rc6 = EVP_PKEY_set1_DH(ephemeralParams, ephemeral_key)
|
||||
|
||||
EVP_PKEY_free(mappingKey)
|
||||
|
||||
var ephemeralKeyPair : OpaquePointer? = nil
|
||||
let pctx = EVP_PKEY_CTX_new(ephemeralParams, nil)
|
||||
EVP_PKEY_keygen_init(pctx)
|
||||
EVP_PKEY_keygen(pctx, &ephemeralKeyPair)
|
||||
EVP_PKEY_CTX_free(pctx)
|
||||
|
||||
EVP_PKEY_free( ephemeralParams )
|
||||
|
||||
let publicKey = OpenSSLUtils.getPublicKeyData( from: ephemeralKeyPair! )
|
||||
print( "Ephemeral public key - \(binToHexRep(publicKey!, asArray: true))")
|
||||
|
||||
return ephemeralKeyPair!
|
||||
}
|
||||
|
||||
func doTest() {
|
||||
var passportEphKey : [UInt8] = [0x01, 0xd5, 0xa8, 0xb2, 0xea, 0xb6, 0x18, 0x55, 0x34, 0x24, 0xfe, 0x25, 0x10, 0x15, 0xaf, 0xc3, 0x85, 0xda, 0x13, 0x94, 0xe7, 0x2b, 0x76, 0x81, 0x2d, 0x8c, 0xe0, 0x6f, 0x60, 0x65, 0xfb, 0x33, 0x8c, 0x5b, 0x2d, 0xc9, 0x38, 0x11, 0xb3, 0x80, 0xd7, 0x49, 0xaa, 0xeb, 0x36, 0xa5, 0xdd, 0xa0, 0x78, 0x33, 0xe0, 0xd5, 0x52, 0xd4, 0x4e, 0xaa, 0xf0, 0xa3, 0x5f, 0xd3, 0x9c, 0x89, 0x44, 0xca, 0xac, 0xf1, 0x7a, 0x1e, 0xd4, 0x61, 0x58, 0x1d, 0x81, 0x83, 0xb6, 0x98, 0x85, 0x15, 0x2d, 0xeb, 0xd7, 0xc2, 0x66, 0xe4, 0xe0, 0xd1, 0x73, 0x1c, 0x52, 0xd7, 0x3a, 0x33, 0x20, 0x1f, 0x64, 0x8b, 0x85, 0xb7, 0xe5, 0xbb, 0x09, 0xe8, 0x8a, 0xd3, 0x79, 0x8c, 0x23, 0x7a, 0x35, 0xb2, 0xc5, 0xfa, 0x42, 0xcb, 0xe4, 0xc4, 0x86, 0xa7, 0x8f, 0x96, 0x22, 0xc1, 0x2b, 0x07, 0xc6, 0x29, 0xa2, 0xfd, 0x31, 0xcb, 0xba, 0x1b, 0x05, 0xca, 0xc2, 0xaa, 0xc3, 0x6f, 0x5a, 0xa8, 0x43, 0xa1, 0x60, 0x35, 0x97, 0xda, 0x35, 0xfd, 0x76, 0x16, 0xa9, 0x32, 0x91, 0xd1, 0xd8, 0x7b, 0x0b, 0xfc, 0x30, 0x99, 0x06, 0xa7, 0x62, 0x44, 0x85, 0x2b, 0xb9, 0x9b, 0x5a, 0xfb, 0x94, 0x28, 0x47, 0x40, 0x7f, 0x7a, 0x6a, 0xb2, 0xe9, 0xcc, 0xe3, 0x13, 0x52, 0x7c, 0xc0, 0x87, 0x1d, 0x72, 0xc5, 0x4b, 0x69, 0x0a, 0x2a, 0xc7, 0x37, 0xd5, 0x17, 0xd2, 0xce, 0xd2, 0x54, 0x66, 0x92, 0x42, 0x91, 0x84, 0x24, 0xef, 0xb6, 0x98, 0x6d, 0x78, 0x95, 0x0d, 0x7e, 0x49, 0xd0, 0xee, 0xcc, 0x61, 0x5d, 0x2f, 0x5a, 0xa1, 0xb2, 0xc0, 0xa9, 0xe7, 0x30, 0x94, 0x58, 0x58, 0x7a, 0x59, 0xd7, 0x96, 0xe9, 0x8c, 0x2c, 0xfd, 0xe9, 0x58, 0xe4, 0x4b, 0xa3, 0x31, 0x47, 0x03, 0x57, 0x05, 0x84, 0x6d, 0x3c, 0x4c, 0x3a, 0xaa, ];
|
||||
|
||||
let ephKeyPair = testDHKeyMapping()
|
||||
|
||||
let passportPublicKey = OpenSSLUtils.decodePublicKeyFromBytes(pubKeyData: passportEphKey, params: ephKeyPair)
|
||||
|
||||
let dh = EVP_PKEY_get1_DH(ephKeyPair);
|
||||
|
||||
var out = [UInt8](repeating:0, count:Int(DH_size(dh)))
|
||||
|
||||
let dh_ppub = EVP_PKEY_get1_DH(passportPublicKey)
|
||||
var bn = BN_new()
|
||||
DH_get0_key( dh_ppub, &bn, nil )
|
||||
|
||||
let len = DH_compute_key(&out, bn, dh);
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
22
app/ios/Examples/Example_CocoaPods/Podfile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Uncomment the next line to define a global platform for your project
|
||||
platform :ios, '15.0'
|
||||
|
||||
# Disable use of input/output files here so that when we build it includes any changes to the development pod
|
||||
# rather than having to manually clean and rebuuild each time
|
||||
# Note this is commented out as it breaks archive project! But useful for dev
|
||||
#install! 'cocoapods', :disable_input_output_paths => true
|
||||
|
||||
target 'NFCPassportReaderApp' do
|
||||
# Comment the next line if you don't want to use dynamic frameworks
|
||||
use_frameworks!
|
||||
|
||||
# Pods for NFCPassportReaderApp
|
||||
pod 'NFCPassportReader', :path => '../..'
|
||||
pod 'QKMRZScanner'
|
||||
|
||||
target 'NFCPassportReaderAppTests' do
|
||||
inherit! :search_paths
|
||||
# Pods for testing
|
||||
end
|
||||
end
|
||||
|
||||
35
app/ios/Examples/Example_CocoaPods/Podfile.lock
Normal file
@@ -0,0 +1,35 @@
|
||||
PODS:
|
||||
- NFCPassportReader (1.1.9):
|
||||
- OpenSSL-Universal (= 1.1.180)
|
||||
- OpenSSL-Universal (1.1.180)
|
||||
- QKMRZParser (2.0.0)
|
||||
- QKMRZScanner (3.0.0):
|
||||
- QKMRZParser (~> 2.0.0)
|
||||
- SwiftyTesseract (~> 3.1.3)
|
||||
- SwiftyTesseract (3.1.3)
|
||||
|
||||
DEPENDENCIES:
|
||||
- NFCPassportReader (from `../..`)
|
||||
- QKMRZScanner
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- OpenSSL-Universal
|
||||
- QKMRZParser
|
||||
- QKMRZScanner
|
||||
- SwiftyTesseract
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
NFCPassportReader:
|
||||
:path: "../.."
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
NFCPassportReader: 3a4b15d28c89a1f747c957f2bce1230c268dba25
|
||||
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
||||
QKMRZParser: 6b419b6f07d6bff6b50429b97de10846dc902c29
|
||||
QKMRZScanner: cf2348fd6ce441e758328da4adf231ef2b51d769
|
||||
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
|
||||
|
||||
PODFILE CHECKSUM: b90c09d0214453ca8e10fa6c4bc0d09e4919d7a1
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
2
app/ios/Examples/Example_CocoaPods/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
The CocoaPods example is here purely informational - no real updates will be done to it.
|
||||
|
||||
@@ -0,0 +1,667 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
A117B7EB2695AD2400E13C18 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A117B7E62695AD2400E13C18 /* ViewController.swift */; };
|
||||
A117B7EC2695AD2400E13C18 /* PreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A117B7E72695AD2400E13C18 /* PreviewView.swift */; };
|
||||
A117B7ED2695AD2400E13C18 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = A117B7E82695AD2400E13C18 /* LICENSE */; };
|
||||
A117B7EE2695AD2400E13C18 /* VisionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A117B7E92695AD2400E13C18 /* VisionViewController.swift */; };
|
||||
A117B7EF2695AD2400E13C18 /* StringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A117B7EA2695AD2400E13C18 /* StringUtils.swift */; };
|
||||
A117B7F22695AE2300E13C18 /* MRZParser in Frameworks */ = {isa = PBXBuildFile; productRef = A117B7F12695AE2300E13C18 /* MRZParser */; };
|
||||
A1298C9F25D53A5C00F5713E /* ViewExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1298C9E25D53A5C00F5713E /* ViewExt.swift */; };
|
||||
A13F2A22268EF8BA0097C2D1 /* NFCPassportReader in Frameworks */ = {isa = PBXBuildFile; productRef = A13F2A21268EF8BA0097C2D1 /* NFCPassportReader */; };
|
||||
A1614B9225D5856600191749 /* ExportPassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1614B9125D5856600191749 /* ExportPassportView.swift */; };
|
||||
A16EB23122A9E9E10008F53F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16EB23022A9E9E10008F53F /* AppDelegate.swift */; };
|
||||
A16EB23322A9E9E10008F53F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A16EB23222A9E9E10008F53F /* SceneDelegate.swift */; };
|
||||
A16EB23A22A9E9E20008F53F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A16EB23922A9E9E20008F53F /* Assets.xcassets */; };
|
||||
A16EB23D22A9E9E20008F53F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */; };
|
||||
A17134BE22C8EF7200C457C3 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17134BD22C8EF7100C457C3 /* MainView.swift */; };
|
||||
A17134C022C8F0A600C457C3 /* PassportUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17134BF22C8F0A600C457C3 /* PassportUtils.swift */; };
|
||||
A17375F525F78B0D005995DA /* PACETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A17375F425F78B0C005995DA /* PACETests.swift */; };
|
||||
A1769DF725D3E318006002D1 /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1769DF625D3E318006002D1 /* SettingsStore.swift */; };
|
||||
A1816E9C22C9059F00F546A0 /* PassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1816E9B22C9059F00F546A0 /* PassportView.swift */; };
|
||||
A18248C22369D17300581384 /* DetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A18248C12369D17300581384 /* DetailsView.swift */; };
|
||||
A182DE6125DD6F1300341204 /* StoredPassportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A182DE6025DD6F1300341204 /* StoredPassportView.swift */; };
|
||||
A182DE6325DD730D00341204 /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A182DE6225DD730D00341204 /* FileManagerExt.swift */; };
|
||||
A1A13B9525B8A29E0026074C /* UIApplicationExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */; };
|
||||
A1A4C0F725B5E4D70070908B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4C0F625B5E4D70070908B /* Foundation.framework */; };
|
||||
A1C234C225DD19DE003FFD79 /* PassportSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */; };
|
||||
A1CE83AC22C91D1300E3EACF /* StringExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1CE83AB22C91D1300E3EACF /* StringExt.swift */; };
|
||||
A1DD3F3F22C535F10067255C /* masterList.pem in Resources */ = {isa = PBXBuildFile; fileRef = A1DD3F3E22C535F00067255C /* masterList.pem */; };
|
||||
A1EBC5242370BAB2004DD19E /* DataGroupParsingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */; };
|
||||
A1EBC5252370BAB2004DD19E /* NFCPassportReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */; };
|
||||
A1FDC52E25D3F15D00D22FF4 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */; };
|
||||
A1FDC53225D3F19E00D22FF4 /* ViewModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */; };
|
||||
A1FDC53425D3F1DE00D22FF4 /* CheckBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */; };
|
||||
A1FDC53625D43AB400D22FF4 /* MRZEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
A1EBC5122370B88D004DD19E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = A16EB22522A9E9E10008F53F /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = A16EB22C22A9E9E10008F53F;
|
||||
remoteInfo = NFCPassportReaderApp;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
A117B7E62695AD2400E13C18 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
A117B7E72695AD2400E13C18 /* PreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewView.swift; sourceTree = "<group>"; };
|
||||
A117B7E82695AD2400E13C18 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||
A117B7E92695AD2400E13C18 /* VisionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisionViewController.swift; sourceTree = "<group>"; };
|
||||
A117B7EA2695AD2400E13C18 /* StringUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringUtils.swift; sourceTree = "<group>"; };
|
||||
A1298C9E25D53A5C00F5713E /* ViewExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExt.swift; sourceTree = "<group>"; };
|
||||
A1614B9125D5856600191749 /* ExportPassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportPassportView.swift; sourceTree = "<group>"; };
|
||||
A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NFCPassportReaderApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A16EB23022A9E9E10008F53F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
A16EB23222A9E9E10008F53F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
A16EB23922A9E9E20008F53F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
A16EB23C22A9E9E20008F53F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
A16EB23E22A9E9E20008F53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A16EB24422A9EA000008F53F /* NFCPassportReader.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NFCPassportReader.entitlements; sourceTree = "<group>"; };
|
||||
A17134BD22C8EF7100C457C3 /* MainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||
A17134BF22C8F0A600C457C3 /* PassportUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PassportUtils.swift; sourceTree = "<group>"; };
|
||||
A17375F425F78B0C005995DA /* PACETests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PACETests.swift; sourceTree = "<group>"; };
|
||||
A1769DF625D3E318006002D1 /* SettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStore.swift; sourceTree = "<group>"; };
|
||||
A1816E9B22C9059F00F546A0 /* PassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportView.swift; sourceTree = "<group>"; };
|
||||
A18248C12369D17300581384 /* DetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailsView.swift; sourceTree = "<group>"; };
|
||||
A182DE6025DD6F1300341204 /* StoredPassportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredPassportView.swift; sourceTree = "<group>"; };
|
||||
A182DE6225DD730D00341204 /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; };
|
||||
A182DE6725DD7EA600341204 /* MRZScannerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MRZScannerViewController.swift; sourceTree = "<group>"; };
|
||||
A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExt.swift; sourceTree = "<group>"; };
|
||||
A1A4C0F625B5E4D70070908B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
A1AE9E142686235E00D0E764 /* NFCPassportReader */ = {isa = PBXFileReference; lastKnownFileType = folder; name = NFCPassportReader; path = ../..; sourceTree = "<group>"; };
|
||||
A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PassportSummaryView.swift; sourceTree = "<group>"; };
|
||||
A1CE83AB22C91D1300E3EACF /* StringExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExt.swift; sourceTree = "<group>"; };
|
||||
A1DD3F3E22C535F00067255C /* masterList.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = masterList.pem; sourceTree = "<group>"; };
|
||||
A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NFCPassportReaderAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A1EBC5112370B88D004DD19E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataGroupParsingTests.swift; sourceTree = "<group>"; };
|
||||
A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NFCPassportReaderTests.swift; sourceTree = "<group>"; };
|
||||
A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifiers.swift; sourceTree = "<group>"; };
|
||||
A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxView.swift; sourceTree = "<group>"; };
|
||||
A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MRZEntryView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
A16EB22A22A9E9E10008F53F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A1A4C0F725B5E4D70070908B /* Foundation.framework in Frameworks */,
|
||||
A117B7F22695AE2300E13C18 /* MRZParser in Frameworks */,
|
||||
A13F2A22268EF8BA0097C2D1 /* NFCPassportReader in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC50A2370B88D004DD19E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
A117B7E52695AD2400E13C18 /* MrzScanner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A117B7E62695AD2400E13C18 /* ViewController.swift */,
|
||||
A117B7E72695AD2400E13C18 /* PreviewView.swift */,
|
||||
A117B7E82695AD2400E13C18 /* LICENSE */,
|
||||
A117B7E92695AD2400E13C18 /* VisionViewController.swift */,
|
||||
A117B7EA2695AD2400E13C18 /* StringUtils.swift */,
|
||||
);
|
||||
path = MrzScanner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1298C9B25D539CD00F5713E /* HelperViews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1FDC53325D3F1DE00D22FF4 /* CheckBoxView.swift */,
|
||||
A1298C9E25D53A5C00F5713E /* ViewExt.swift */,
|
||||
A1FDC53125D3F19E00D22FF4 /* ViewModifiers.swift */,
|
||||
);
|
||||
path = HelperViews;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22422A9E9E10008F53F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1AE9E142686235E00D0E764 /* NFCPassportReader */,
|
||||
A16EB22F22A9E9E10008F53F /* NFCPassportReaderApp */,
|
||||
A1EBC50E2370B88D004DD19E /* NFCPassportReaderAppTests */,
|
||||
A16EB22E22A9E9E10008F53F /* Products */,
|
||||
A1A4C0E325B5D3370070908B /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22E22A9E9E10008F53F /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */,
|
||||
A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A16EB22F22A9E9E10008F53F /* NFCPassportReaderApp */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A16EB24422A9EA000008F53F /* NFCPassportReader.entitlements */,
|
||||
A117B7E52695AD2400E13C18 /* MrzScanner */,
|
||||
A1CE83AF22C91DB600E3EACF /* Model */,
|
||||
A182DE6425DD731900341204 /* Extensions */,
|
||||
A1CE83B022C91DF100E3EACF /* Views */,
|
||||
A16EB23022A9E9E10008F53F /* AppDelegate.swift */,
|
||||
A16EB23222A9E9E10008F53F /* SceneDelegate.swift */,
|
||||
A16EB23922A9E9E20008F53F /* Assets.xcassets */,
|
||||
A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */,
|
||||
A16EB23E22A9E9E20008F53F /* Info.plist */,
|
||||
A1DD3F3E22C535F00067255C /* masterList.pem */,
|
||||
);
|
||||
path = NFCPassportReaderApp;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A182DE6425DD731900341204 /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1CE83AB22C91D1300E3EACF /* StringExt.swift */,
|
||||
A182DE6225DD730D00341204 /* FileManagerExt.swift */,
|
||||
A1A13B9425B8A29E0026074C /* UIApplicationExt.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1A4C0E325B5D3370070908B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1A4C0F625B5E4D70070908B /* Foundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1CE83AF22C91DB600E3EACF /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A17134BF22C8F0A600C457C3 /* PassportUtils.swift */,
|
||||
A1769DF625D3E318006002D1 /* SettingsStore.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1CE83B022C91DF100E3EACF /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1298C9B25D539CD00F5713E /* HelperViews */,
|
||||
A17134BD22C8EF7100C457C3 /* MainView.swift */,
|
||||
A1FDC53525D43AB400D22FF4 /* MRZEntryView.swift */,
|
||||
A1FDC52D25D3F15D00D22FF4 /* SettingsView.swift */,
|
||||
A1816E9B22C9059F00F546A0 /* PassportView.swift */,
|
||||
A1C234C125DD19DE003FFD79 /* PassportSummaryView.swift */,
|
||||
A18248C12369D17300581384 /* DetailsView.swift */,
|
||||
A182DE6025DD6F1300341204 /* StoredPassportView.swift */,
|
||||
A1614B9125D5856600191749 /* ExportPassportView.swift */,
|
||||
A182DE6725DD7EA600341204 /* MRZScannerViewController.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A1EBC50E2370B88D004DD19E /* NFCPassportReaderAppTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A1EBC5212370BAB2004DD19E /* DataGroupParsingTests.swift */,
|
||||
A1EBC5222370BAB2004DD19E /* NFCPassportReaderTests.swift */,
|
||||
A17375F425F78B0C005995DA /* PACETests.swift */,
|
||||
A1EBC5112370B88D004DD19E /* Info.plist */,
|
||||
);
|
||||
path = NFCPassportReaderAppTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A16EB24122A9E9E20008F53F /* Build configuration list for PBXNativeTarget "NFCPassportReaderApp" */;
|
||||
buildPhases = (
|
||||
A16EB22922A9E9E10008F53F /* Sources */,
|
||||
A16EB22A22A9E9E10008F53F /* Frameworks */,
|
||||
A16EB22B22A9E9E10008F53F /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = NFCPassportReaderApp;
|
||||
packageProductDependencies = (
|
||||
A13F2A21268EF8BA0097C2D1 /* NFCPassportReader */,
|
||||
A117B7F12695AE2300E13C18 /* MRZParser */,
|
||||
);
|
||||
productName = NFCTest;
|
||||
productReference = A16EB22D22A9E9E10008F53F /* NFCPassportReaderApp.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
A1EBC50C2370B88D004DD19E /* NFCPassportReaderAppTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A1EBC5162370B88D004DD19E /* Build configuration list for PBXNativeTarget "NFCPassportReaderAppTests" */;
|
||||
buildPhases = (
|
||||
A1EBC5092370B88D004DD19E /* Sources */,
|
||||
A1EBC50A2370B88D004DD19E /* Frameworks */,
|
||||
A1EBC50B2370B88D004DD19E /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
A1EBC5132370B88D004DD19E /* PBXTargetDependency */,
|
||||
);
|
||||
name = NFCPassportReaderAppTests;
|
||||
productName = NFCPassportReaderAppTests;
|
||||
productReference = A1EBC50D2370B88D004DD19E /* NFCPassportReaderAppTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
A16EB22522A9E9E10008F53F /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1120;
|
||||
LastUpgradeCheck = 1300;
|
||||
ORGANIZATIONNAME = "Andy Qua";
|
||||
TargetAttributes = {
|
||||
A16EB22C22A9E9E10008F53F = {
|
||||
CreatedOnToolsVersion = 11.0;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
A1EBC50C2370B88D004DD19E = {
|
||||
CreatedOnToolsVersion = 11.2;
|
||||
TestTargetID = A16EB22C22A9E9E10008F53F;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = A16EB22822A9E9E10008F53F /* Build configuration list for PBXProject "NFCPassportReaderApp" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = A16EB22422A9E9E10008F53F;
|
||||
packageReferences = (
|
||||
A183989A26848C7600DC98C1 /* XCRemoteSwiftPackageReference "NFCPassportReader" */,
|
||||
A117B7F02695AE2300E13C18 /* XCRemoteSwiftPackageReference "MRZParser" */,
|
||||
);
|
||||
productRefGroup = A16EB22E22A9E9E10008F53F /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */,
|
||||
A1EBC50C2370B88D004DD19E /* NFCPassportReaderAppTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
A16EB22B22A9E9E10008F53F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A16EB23D22A9E9E20008F53F /* LaunchScreen.storyboard in Resources */,
|
||||
A1DD3F3F22C535F10067255C /* masterList.pem in Resources */,
|
||||
A117B7ED2695AD2400E13C18 /* LICENSE in Resources */,
|
||||
A16EB23A22A9E9E20008F53F /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC50B2370B88D004DD19E /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
A16EB22922A9E9E10008F53F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A1CE83AC22C91D1300E3EACF /* StringExt.swift in Sources */,
|
||||
A117B7EB2695AD2400E13C18 /* ViewController.swift in Sources */,
|
||||
A1FDC53625D43AB400D22FF4 /* MRZEntryView.swift in Sources */,
|
||||
A17134BE22C8EF7200C457C3 /* MainView.swift in Sources */,
|
||||
A117B7EE2695AD2400E13C18 /* VisionViewController.swift in Sources */,
|
||||
A16EB23122A9E9E10008F53F /* AppDelegate.swift in Sources */,
|
||||
A117B7EC2695AD2400E13C18 /* PreviewView.swift in Sources */,
|
||||
A1816E9C22C9059F00F546A0 /* PassportView.swift in Sources */,
|
||||
A117B7EF2695AD2400E13C18 /* StringUtils.swift in Sources */,
|
||||
A1769DF725D3E318006002D1 /* SettingsStore.swift in Sources */,
|
||||
A1298C9F25D53A5C00F5713E /* ViewExt.swift in Sources */,
|
||||
A182DE6325DD730D00341204 /* FileManagerExt.swift in Sources */,
|
||||
A1FDC52E25D3F15D00D22FF4 /* SettingsView.swift in Sources */,
|
||||
A182DE6125DD6F1300341204 /* StoredPassportView.swift in Sources */,
|
||||
A1FDC53225D3F19E00D22FF4 /* ViewModifiers.swift in Sources */,
|
||||
A1C234C225DD19DE003FFD79 /* PassportSummaryView.swift in Sources */,
|
||||
A1614B9225D5856600191749 /* ExportPassportView.swift in Sources */,
|
||||
A18248C22369D17300581384 /* DetailsView.swift in Sources */,
|
||||
A1FDC53425D3F1DE00D22FF4 /* CheckBoxView.swift in Sources */,
|
||||
A1A13B9525B8A29E0026074C /* UIApplicationExt.swift in Sources */,
|
||||
A16EB23322A9E9E10008F53F /* SceneDelegate.swift in Sources */,
|
||||
A17134C022C8F0A600C457C3 /* PassportUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A1EBC5092370B88D004DD19E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A1EBC5252370BAB2004DD19E /* NFCPassportReaderTests.swift in Sources */,
|
||||
A17375F525F78B0D005995DA /* PACETests.swift in Sources */,
|
||||
A1EBC5242370BAB2004DD19E /* DataGroupParsingTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
A1EBC5132370B88D004DD19E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = A16EB22C22A9E9E10008F53F /* NFCPassportReaderApp */;
|
||||
targetProxy = A1EBC5122370B88D004DD19E /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
A16EB23B22A9E9E20008F53F /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
A16EB23C22A9E9E20008F53F /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
A16EB23F22A9E9E20008F53F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
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;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A16EB24022A9E9E20008F53F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
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;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A16EB24222A9E9E20008F53F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NFCPassportReaderApp/NFCPassportReader.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.nfcpassportreader;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A16EB24322A9E9E20008F53F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = NFCPassportReaderApp/NFCPassportReader.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.nfcpassportreader;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A1EBC5142370B88D004DD19E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.NFCPassportReaderAppTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NFCPassportReaderApp.app/NFCPassportReaderApp";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A1EBC5152370B88D004DD19E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = A4ZM73UFF5;
|
||||
INFOPLIST_FILE = NFCPassportReaderAppTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.andyqua.NFCPassportReaderAppTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NFCPassportReaderApp.app/NFCPassportReaderApp";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
A16EB22822A9E9E10008F53F /* Build configuration list for PBXProject "NFCPassportReaderApp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A16EB23F22A9E9E20008F53F /* Debug */,
|
||||
A16EB24022A9E9E20008F53F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A16EB24122A9E9E20008F53F /* Build configuration list for PBXNativeTarget "NFCPassportReaderApp" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A16EB24222A9E9E20008F53F /* Debug */,
|
||||
A16EB24322A9E9E20008F53F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A1EBC5162370B88D004DD19E /* Build configuration list for PBXNativeTarget "NFCPassportReaderAppTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A1EBC5142370B88D004DD19E /* Debug */,
|
||||
A1EBC5152370B88D004DD19E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
A117B7F02695AE2300E13C18 /* XCRemoteSwiftPackageReference "MRZParser" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/appintheair/MRZParser";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
A183989A26848C7600DC98C1 /* XCRemoteSwiftPackageReference "NFCPassportReader" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/AndyQ/NFCPassportReader";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
A117B7F12695AE2300E13C18 /* MRZParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = A117B7F02695AE2300E13C18 /* XCRemoteSwiftPackageReference "MRZParser" */;
|
||||
productName = MRZParser;
|
||||
};
|
||||
A13F2A21268EF8BA0097C2D1 /* NFCPassportReader */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = NFCPassportReader;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = A16EB22522A9E9E10008F53F /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "NFCPassportReaderTests"
|
||||
BuildableName = "NFCPassportReaderTests"
|
||||
BlueprintName = "NFCPassportReaderTests"
|
||||
ReferencedContainer = "container:..">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A1EBC50C2370B88D004DD19E"
|
||||
BuildableName = "NFCPassportReaderAppTests.xctest"
|
||||
BlueprintName = "NFCPassportReaderAppTests"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
disableMainThreadChecker = "YES"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "OS_ACTIVITY_MODE"
|
||||
value = "disable"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A16EB22C22A9E9E10008F53F"
|
||||
BuildableName = "NFCPassportReaderApp.app"
|
||||
BlueprintName = "NFCPassportReaderApp"
|
||||
ReferencedContainer = "container:NFCPassportReaderApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 06/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreNFC
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
// Called when a new scene session is being created.
|
||||
// Use this method to select a configuration to create the new scene with.
|
||||
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
// Called when the user discards a scene session.
|
||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"images" : [
|
||||
{
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-40.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-40@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-60@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-72.png",
|
||||
"size" : "72x72",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"idiom" : "ipad",
|
||||
"size" : "72x72",
|
||||
"filename" : "icon-72@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x",
|
||||
"filename" : "icon-76.png"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-76@2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "50x50",
|
||||
"filename" : "icon-small-50.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-small-50@2x.png",
|
||||
"size" : "50x50",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"scale" : "1x",
|
||||
"filename" : "icon-small.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-small@2x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "57x57",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"scale" : "2x",
|
||||
"size" : "57x57",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon@2x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-small@3x.png",
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"scale" : "3x",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-40@3x.png"
|
||||
},
|
||||
{
|
||||
"filename" : "icon-60@3x.png",
|
||||
"scale" : "3x",
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"filename" : "icon-40@2x.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"scale" : "1x",
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"filename" : "icon-small.png"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"scale" : "2x",
|
||||
"filename" : "icon-small@2x.png",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-83.5@2x.png",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"filename" : "notification-icon@2x.png",
|
||||
"idiom" : "iphone"
|
||||
},
|
||||
{
|
||||
"scale" : "3x",
|
||||
"filename" : "notification-icon@3x.png",
|
||||
"idiom" : "iphone",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "notification-icon~ipad.png",
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "notification-icon~ipad@2x.png",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x",
|
||||
"idiom" : "ipad"
|
||||
},
|
||||
{
|
||||
"filename" : "ios-marketing.png",
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 370 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 723 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "background.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
app/ios/Examples/Example_SPM/NFCPassportReaderApp/Assets.xcassets/background.imageset/background.png
vendored
Normal file
|
After Width: | Height: | Size: 387 KiB |
21
app/ios/Examples/Example_SPM/NFCPassportReaderApp/Assets.xcassets/head.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "head.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
app/ios/Examples/Example_SPM/NFCPassportReaderApp/Assets.xcassets/head.imageset/head.png
vendored
Normal file
|
After Width: | Height: | Size: 187 KiB |
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// FileManagerExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 17/02/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
extension FileManager {
|
||||
static var cachesFolder : URL {
|
||||
FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// StringExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 30/06/2019.
|
||||
// Copyright © 2019 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Some Utility methods for string - access characters by index
|
||||
extension String {
|
||||
subscript(_ i: Int) -> String {
|
||||
let idx1 = index(startIndex, offsetBy: i)
|
||||
let idx2 = index(idx1, offsetBy: 1)
|
||||
return String(self[idx1..<idx2])
|
||||
}
|
||||
|
||||
subscript (bounds: CountableRange<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
return String(self[start..<end])
|
||||
}
|
||||
|
||||
subscript (bounds: CountableClosedRange<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
let end = index(startIndex, offsetBy: bounds.upperBound)
|
||||
return String(self[start...end])
|
||||
}
|
||||
|
||||
subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
|
||||
let start = index(startIndex, offsetBy: bounds.lowerBound)
|
||||
return String(self[start...])
|
||||
}
|
||||
|
||||
func strip() -> String {
|
||||
let trimmed = self.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// UIApplicationExt.swift
|
||||
// NFCPassportReaderApp
|
||||
//
|
||||
// Created by Andy Qua on 20/01/2021.
|
||||
// Copyright © 2021 Andy Qua. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIApplication {
|
||||
static var release: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String? ?? "x.x"
|
||||
}
|
||||
static var build: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as! String? ?? "x"
|
||||
}
|
||||
static var version: String {
|
||||
return "\(release).\(build)"
|
||||
}
|
||||
}
|
||||
77
app/ios/Examples/Example_SPM/NFCPassportReaderApp/Info.plist
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>NFCPassportReaderApp</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NFCReaderUsageDescription</key>
|
||||
<string>This app uses NFC to scan passports</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>This app uses the camera to read passports</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>nfc</string>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
|
||||
<array>
|
||||
<string>A0000002471001</string>
|
||||
<string>A0000002472001</string>
|
||||
<string>00000000000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||