From 3cda1bd6b476a8aa139a6b4a8fe08a656c7bafab Mon Sep 17 00:00:00 2001 From: James Sherlock Date: Sun, 13 May 2018 16:48:56 +0100 Subject: [PATCH] Initial extraction of certificate information Closes #9 Currently only the summary and expiration date are extracted, though the door is open for futher improvements! --- .../Model/DeveloperCertificate.swift | 2 + .../Model/SecureCertificate.swift | 69 +++++++++++++++++++ .../SwiftyProvisioningProfileTests.swift | 2 +- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 Sources/SwiftyProvisioningProfile/Model/SecureCertificate.swift diff --git a/Sources/SwiftyProvisioningProfile/Model/DeveloperCertificate.swift b/Sources/SwiftyProvisioningProfile/Model/DeveloperCertificate.swift index 7265646..f2d7e87 100644 --- a/Sources/SwiftyProvisioningProfile/Model/DeveloperCertificate.swift +++ b/Sources/SwiftyProvisioningProfile/Model/DeveloperCertificate.swift @@ -10,12 +10,14 @@ import Foundation public struct DeveloperCertificate: Codable, Equatable { public let data: Data + public let certificate: SecureCertificate? // MARK: - Codable public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() data = try container.decode(Data.self) + certificate = try? SecureCertificate(base64EncodedData: data) } public func encode(to encoder: Encoder) throws { diff --git a/Sources/SwiftyProvisioningProfile/Model/SecureCertificate.swift b/Sources/SwiftyProvisioningProfile/Model/SecureCertificate.swift new file mode 100644 index 0000000..df1d118 --- /dev/null +++ b/Sources/SwiftyProvisioningProfile/Model/SecureCertificate.swift @@ -0,0 +1,69 @@ +// +// SecureCertificate.swift +// SwiftyProvisioningProfile +// +// Created by Sherlock, James on 13/05/2018. +// + +import Foundation + +public struct SecureCertificate: CustomStringConvertible, Equatable { + + public enum CertificateError: Error { + case failedToCreate + case failedToObtainSummary + case failedToObtainValues + } + + public let summary: String + public let expiryDate: Date? + + public init(base64EncodedData: Data) throws { + + // Create Certificate + + guard let certificate = SecCertificateCreateWithData(nil, base64EncodedData as CFData) else { + throw CertificateError.failedToCreate + } + + // Error + + var error: Unmanaged? + + func checkError() throws { + if let error = error { + throw error.takeUnretainedValue() + } + } + + // Summary + + guard let summary = SecCertificateCopySubjectSummary(certificate) else { + throw CertificateError.failedToObtainSummary + } + + self.summary = summary as String + + // Values (Expiry) + + let valuesKeys = [ + kSecOIDInvalidityDate + ] as CFArray + + let values = SecCertificateCopyValues(certificate, valuesKeys, &error) + try checkError() + + guard let dictionary = values as? Dictionary else { + throw CertificateError.failedToObtainValues + } + + let expiryDateDictionary = dictionary[kSecOIDInvalidityDate] as? [String: Any] + expiryDate = expiryDateDictionary?["value"] as? Date + + } + + public var description: String { + return "\(summary), Expires: \(expiryDate?.description ?? "No Expiry Date")" + } + +} diff --git a/Tests/SwiftyProvisioningProfileTests/SwiftyProvisioningProfileTests.swift b/Tests/SwiftyProvisioningProfileTests/SwiftyProvisioningProfileTests.swift index 9270cf6..1f5e980 100644 --- a/Tests/SwiftyProvisioningProfileTests/SwiftyProvisioningProfileTests.swift +++ b/Tests/SwiftyProvisioningProfileTests/SwiftyProvisioningProfileTests.swift @@ -33,7 +33,7 @@ class SwiftyProvisioningProfileTests: XCTestCase { let data = try Data(contentsOf: url) let profile = try ProvisioningProfile.parse(from: data) - print(profile) + print(profile.developerCertificates.flatMap({ $0.certificate?.description }).joined(separator: "\n")) } // TODO: Create or find a simple & usable profile and wrtie actual tests for it