diff --git a/QLAppBundle.xcodeproj/project.pbxproj b/QLAppBundle.xcodeproj/project.pbxproj index d0190bb..0c85f37 100644 --- a/QLAppBundle.xcodeproj/project.pbxproj +++ b/QLAppBundle.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 549E3B9F2EBA9D2500ADFF56 /* QLAppBundle Preview Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54442C202E378BAF008A870E /* QLAppBundle Preview Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 549E3BA12EBAE7D300ADFF56 /* URL+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E3BA02EBAE7D300ADFF56 /* URL+File.swift */; }; 549E3BA22EBAECD400ADFF56 /* URL+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E3BA02EBAE7D300ADFF56 /* URL+File.swift */; }; + 549E3BA42EBC021500ADFF56 /* Preview+TransportSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E3BA32EBC021500ADFF56 /* Preview+TransportSecurity.swift */; }; 54AE5BFF2EB3DB1000B4CFC7 /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */; }; 54B6FFEE2EB6A847007397C0 /* AssetCarReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B6FFEC2EB6A847007397C0 /* AssetCarReader.swift */; }; 54B6FFEF2EB6A8E0007397C0 /* CoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54D3A6F52EA4610B001EF4F6 /* CoreUI.framework */; }; @@ -155,6 +156,7 @@ 547F52FC2EB37F3A002B6D5F /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 549E3B9E2EBA8FDA00ADFF56 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 549E3BA02EBAE7D300ADFF56 /* URL+File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+File.swift"; sourceTree = ""; }; + 549E3BA32EBC021500ADFF56 /* Preview+TransportSecurity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preview+TransportSecurity.swift"; sourceTree = ""; }; 54AE5BFB2EB3DB1000B4CFC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54AE5BFC2EB3DB1000B4CFC7 /* QLThumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLThumbnail.entitlements; sourceTree = ""; }; 54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = ""; }; @@ -219,6 +221,7 @@ 547F52DC2EB2C15D002B6D5F /* ExpirationStatus.swift */, 547F52E62EB2C41C002B6D5F /* PreviewGenerator.swift */, 547F52EC2EB2C822002B6D5F /* Preview+AppInfo.swift */, + 549E3BA32EBC021500ADFF56 /* Preview+TransportSecurity.swift */, 547F52EE2EB2C8E8002B6D5F /* Preview+Provisioning.swift */, 547F52F32EB2CA05002B6D5F /* Preview+Entitlements.swift */, 547F52E32EB2C3D8002B6D5F /* Preview+iTunesPurchase.swift */, @@ -533,6 +536,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 549E3BA42EBC021500ADFF56 /* Preview+TransportSecurity.swift in Sources */, 54D3A6F02EA3F49F001EF4F6 /* NSBezierPath+RoundedRect.swift in Sources */, 547F52E42EB2C3D8002B6D5F /* Preview+iTunesPurchase.swift in Sources */, 547F52F72EB2CAC7002B6D5F /* Preview+Footer.swift in Sources */, diff --git a/resources/template.html b/resources/template.html index dfaf690..1aa1b80 100644 --- a/resources/template.html +++ b/resources/template.html @@ -5,7 +5,7 @@ -
+

__QuickLookTitle__

App icon
@@ -34,9 +34,9 @@ Price: __iTunesPrice__
-
+

App Transport Security

- __AppTransportSecurity__ + __TransportSecurityDict__
diff --git a/src/Preview+AppInfo.swift b/src/Preview+AppInfo.swift index 8aeabf8..100d4bd 100644 --- a/src/Preview+AppInfo.swift +++ b/src/Preview+AppInfo.swift @@ -1,61 +1,6 @@ import Foundation -let TransportSecurityLocalizedKeys = [ - "NSAllowsArbitraryLoads": "Allows Arbitrary Loads", - "NSAllowsArbitraryLoadsForMedia": "Allows Arbitrary Loads for Media", - "NSAllowsArbitraryLoadsInWebContent": "Allows Arbitrary Loads in Web Content", - "NSAllowsLocalNetworking": "Allows Local Networking", - "NSExceptionDomains": "Exception Domains", - - "NSIncludesSubdomains": "Includes Subdomains", - "NSRequiresCertificateTransparency": "Requires Certificate Transparency", - - "NSExceptionAllowsInsecureHTTPLoads": "Allows Insecure HTTP Loads", - "NSExceptionMinimumTLSVersion": "Minimum TLS Version", - "NSExceptionRequiresForwardSecrecy": "Requires Forward Secrecy", - - "NSThirdPartyExceptionAllowsInsecureHTTPLoads": "Allows Insecure HTTP Loads", - "NSThirdPartyExceptionMinimumTLSVersion": "Minimum TLS Version", - "NSThirdPartyExceptionRequiresForwardSecrecy": "Requires Forward Secrecy", -] - -/// Print recursive tree of key-value mappings. -private func recursiveTransportSecurity(_ dictionary: [String: Any], _ level: Int = 0) -> String { - var output = "" - for (key, value) in dictionary { - let localizedKey = TransportSecurityLocalizedKeys[key] ?? key - for _ in 0..\n" - output += recursiveTransportSecurity(subDict, level + 1) - output += "
\n" - } else if let number = value as? NSNumber { - output += "\(localizedKey): \(number.boolValue ? "YES" : "NO")
" - } else { - output += "\(localizedKey): \(value)
" - } - } - return output -} - extension PreviewGenerator { - /// @return List of ATS flags. - private func formattedAppTransportSecurity(_ appPlist: PlistDict) -> String { - if let value = appPlist["NSAppTransportSecurity"] as? PlistDict { - return "
\(recursiveTransportSecurity(value))
" - } - - let sdkName = appPlist["DTSDKName"] as? String ?? "0" - let sdkNumber = Double(sdkName.trimmingCharacters(in: .letters)) ?? 0 - if sdkNumber < 9.0 { - return "Not applicable before iOS 9.0" - } - return "No exceptions" - } - private func deviceFamilyList(_ appPlist: PlistDict, isOSX: Bool) -> String { if isOSX { return (appPlist["CFBundleSupportedPlatforms"] as? [String])?.joined(separator: ", ") ?? "macOS" @@ -80,12 +25,14 @@ extension PreviewGenerator { /// Process info stored in `Info.plist` mutating func procAppInfo(_ appPlist: PlistDict?, isOSX: Bool) { guard let appPlist else { + self.apply(["AppInfoHidden": CLASS_HIDDEN]) return } let minVersion = appPlist[isOSX ? "LSMinimumSystemVersion" : "MinimumOSVersion"] as? String ?? "" let extensionType = (appPlist["NSExtension"] as? PlistDict)?["NSExtensionPointIdentifier"] as? String self.apply([ + "AppInfoHidden": CLASS_VISIBLE, "AppName": appPlist["CFBundleDisplayName"] as? String ?? appPlist["CFBundleName"] as? String ?? "", "AppVersion": appPlist["CFBundleShortVersionString"] as? String ?? "", "AppBuildVer": appPlist["CFBundleVersion"] as? String ?? "", @@ -97,7 +44,6 @@ extension PreviewGenerator { "AppDeviceFamily": deviceFamilyList(appPlist, isOSX: isOSX), "AppSDK": appPlist["DTSDKName"] as? String ?? "", "AppMinOS": minVersion, - "AppTransportSecurity": formattedAppTransportSecurity(appPlist), ]) } } diff --git a/src/Preview+TransportSecurity.swift b/src/Preview+TransportSecurity.swift new file mode 100644 index 0000000..b5a4568 --- /dev/null +++ b/src/Preview+TransportSecurity.swift @@ -0,0 +1,70 @@ +import Foundation + +let TransportSecurityLocalizedKeys = [ + "NSAllowsArbitraryLoads": "Allows Arbitrary Loads", + "NSAllowsArbitraryLoadsForMedia": "Allows Arbitrary Loads for Media", + "NSAllowsArbitraryLoadsInWebContent": "Allows Arbitrary Loads in Web Content", + "NSAllowsLocalNetworking": "Allows Local Networking", + "NSExceptionDomains": "Exception Domains", + + "NSIncludesSubdomains": "Includes Subdomains", + "NSRequiresCertificateTransparency": "Requires Certificate Transparency", + + "NSExceptionAllowsInsecureHTTPLoads": "Allows Insecure HTTP Loads", + "NSExceptionMinimumTLSVersion": "Minimum TLS Version", + "NSExceptionRequiresForwardSecrecy": "Requires Forward Secrecy", + + "NSThirdPartyExceptionAllowsInsecureHTTPLoads": "Allows Insecure HTTP Loads", + "NSThirdPartyExceptionMinimumTLSVersion": "Minimum TLS Version", + "NSThirdPartyExceptionRequiresForwardSecrecy": "Requires Forward Secrecy", +] + +/// Print recursive tree of key-value mappings. +private func recursiveTransportSecurity(_ dictionary: [String: Any], _ level: Int = 0) -> String { + var output = "" + for (key, value) in dictionary { + let localizedKey = TransportSecurityLocalizedKeys[key] ?? key + for _ in 0..\n" + output += recursiveTransportSecurity(subDict, level + 1) + output += "
\n" + } else if let number = value as? NSNumber { + output += "\(localizedKey): \(number.boolValue ? "YES" : "NO")
" + } else { + output += "\(localizedKey): \(value)
" + } + } + return output +} + +extension PreviewGenerator { + /// @return List of ATS flags. + private func formattedAppTransportSecurity(_ appPlist: PlistDict) -> String { + if let value = appPlist["NSAppTransportSecurity"] as? PlistDict { + return "
\(recursiveTransportSecurity(value))
" + } + + let sdkName = appPlist["DTSDKName"] as? String ?? "0" + let sdkNumber = Double(sdkName.trimmingCharacters(in: .letters)) ?? 0 + if sdkNumber < 9.0 { + return "Not applicable before iOS 9.0" + } + return "No exceptions" + } + + /// Process ATS info in `Info.plist` + mutating func procTransportSecurity(_ appPlist: PlistDict?) { + guard let appPlist else { + self.apply(["TransportSecurityHidden": CLASS_HIDDEN]) + return + } + self.apply([ + "TransportSecurityHidden": CLASS_VISIBLE, + "TransportSecurityDict": formattedAppTransportSecurity(appPlist), + ]) + } +} diff --git a/src/PreviewGenerator.swift b/src/PreviewGenerator.swift index 2b23c83..4314f57 100644 --- a/src/PreviewGenerator.swift +++ b/src/PreviewGenerator.swift @@ -17,8 +17,9 @@ struct PreviewGenerator { procAppInfo(plistApp, isOSX: meta.isOSX) procItunesMeta(plistItunes) - procProvision(plistProvision, isOSX: meta.isOSX) + procTransportSecurity(plistApp) procEntitlements(meta, plistApp, plistProvision) + procProvision(plistProvision, isOSX: meta.isOSX) procFileInfo(meta.url) procFooterInfo() // App Icon (last, because the image uses a lot of memory)