diff --git a/Package.swift b/Package.swift index b8ff00e..502db4a 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,6 @@ let package = Package( dependencies: [ .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-beta"), .package(url: "https://github.com/vapor/fluent.git", from: "4.0.0-beta"), - //.package(url: "https://github.com/vapor/toolbox.git", from: "18.0.0-beta"), .package(url: "https://github.com/vapor/apns.git", from: "1.0.0-beta"), .package(url: "https://github.com/apple/swift-log.git", from: "1.0.0") ], diff --git a/Sources/PassKit/PassKit.swift b/Sources/PassKit/PassKit.swift index f9da884..0bf41ae 100644 --- a/Sources/PassKit/PassKit.swift +++ b/Sources/PassKit/PassKit.swift @@ -124,18 +124,33 @@ public class PassKitCustom whe /// /// - Parameters: /// - middleware: The `Middleware` which will control authentication for the routes. + /// - Throws: An error of type `PassKitError` public func registerPushRoutes(middleware: Middleware) throws { - let privateKeyPath = URL(fileURLWithPath: delegate.pemPrivateKey, relativeTo: delegate.sslSigningFilesDirectory).unixPath() + let privateKeyPath = URL(fileURLWithPath: delegate.pemPrivateKey, relativeTo: + delegate.sslSigningFilesDirectory).unixPath() + + guard FileManager.default.fileExists(atPath: privateKeyPath) else { + throw PassKitError.pemPrivateKeyMissing + } + let pemPath = URL(fileURLWithPath: delegate.pemCertificate, relativeTo: delegate.sslSigningFilesDirectory).unixPath() - + + guard FileManager.default.fileExists(atPath: privateKeyPath) else { + throw PassKitError.pemCertificateMissing + } + // PassKit *only* works with the production APNs. You can't pass in .sandbox here. if app.apns.configuration == nil { - if let pwd = delegate.pemPrivateKeyPassword { - app.apns.configuration = try .init(privateKeyPath: privateKeyPath, pemPath: pemPath, topic: "", environment: .production, logger: logger) { - $0(pwd.utf8) + do { + if let pwd = delegate.pemPrivateKeyPassword { + app.apns.configuration = try .init(privateKeyPath: privateKeyPath, pemPath: pemPath, topic: "", environment: .production, logger: logger) { + $0(pwd.utf8) + } + } else { + app.apns.configuration = try .init(privateKeyPath: privateKeyPath, pemPath: pemPath, topic: "", environment: .production, logger: logger) } - } else { - app.apns.configuration = try .init(privateKeyPath: privateKeyPath, pemPath: pemPath, topic: "", environment: .production, logger: logger) + } catch { + throw PassKitError.nioPrivateKeyReadFailed(error) } } @@ -437,10 +452,16 @@ public class PassKitCustom whe // If the caller's delegate generated a file we don't have to do it. return } - + + let sslBinary = delegate.sslBinary + + guard FileManager.default.fileExists(atPath: sslBinary.unixPath()) else { + throw PassKitError.opensslBinaryMissing + } + let proc = Process() proc.currentDirectoryURL = delegate.sslSigningFilesDirectory - proc.executableURL = delegate.sslBinary + proc.executableURL = sslBinary proc.arguments = [ "smime", "-binary", "-sign", @@ -462,9 +483,14 @@ public class PassKitCustom whe } private func zip(directory: URL, to: URL) throws { + let zipBinary = delegate.zipBinary + guard FileManager.default.fileExists(atPath: zipBinary.unixPath()) else { + throw PassKitError.zipBinaryMissing + } + let proc = Process() proc.currentDirectoryURL = directory - proc.executableURL = delegate.zipBinary + proc.executableURL = zipBinary proc.arguments = [ to.unixPath(), "-r", "-q", "." ] @@ -472,11 +498,6 @@ public class PassKitCustom whe proc.waitUntilExit() } - enum PassKitError: Error { - case templateNotDirectory - case failedToZipPass - } - private func generatePassContent(for pass: P, on db: Database) -> EventLoopFuture { let tmp = FileManager.default.temporaryDirectory let root = tmp.appendingPathComponent(UUID().uuidString, isDirectory: true) @@ -485,8 +506,12 @@ public class PassKitCustom whe return delegate.template(for: pass, db: db) .flatMap { src in - guard src.hasDirectoryPath else { - return db.eventLoop.makeFailedFuture(PassKitError.templateNotDirectory) + var isDir: ObjCBool = false + + guard src.hasDirectoryPath && + FileManager.default.fileExists(atPath: src.unixPath(), isDirectory: &isDir) && + isDir.boolValue else { + return db.eventLoop.makeFailedFuture(PassKitError.templateNotDirectory) } return self.delegate.encode(pass: pass, db: db, encoder: encoder) diff --git a/Sources/PassKit/PassKitError.swift b/Sources/PassKit/PassKitError.swift new file mode 100644 index 0000000..1aef5ef --- /dev/null +++ b/Sources/PassKit/PassKitError.swift @@ -0,0 +1,28 @@ +// +// File.swift +// +// +// Created by Scott Grosch on 1/22/20. +// + +import Foundation + +public enum PassKitError: Error { + /// The template path is not a directory + case templateNotDirectory + + /// The `pemCertificate` file is missing. + case pemCertificateMissing + + /// The `pemPrivateKey` file is missing. + case pemPrivateKeyMissing + + /// Swift NIO failed to read the key. + case nioPrivateKeyReadFailed(Error) + + /// The path to the zip binary is incorrect. + case zipBinaryMissing + + /// The path to the openssl binary is incorrect + case opensslBinaryMissing +}