Skip to content

Commit

Permalink
Simplify signing and notifications APIs (#17)
Browse files Browse the repository at this point in the history
* Test localization

* Simplify signing

* Simplify notifications API

* Update DocC

* Update Zip

* Rename `openSSLURL` to `openSSLPath`

* Unify error types
  • Loading branch information
fpseverino authored Dec 1, 2024
1 parent 53e9146 commit 61371c3
Show file tree
Hide file tree
Showing 31 changed files with 590 additions and 770 deletions.
3 changes: 1 addition & 2 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
version: 1
builder:
configs:
- documentation_targets: [PassKit, Passes, Orders]
swift_version: 6.0
- documentation_targets: [PassKit, Passes, Orders]
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
.package(url: "https://github.com/vapor/vapor.git", from: "4.106.1"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.12.0"),
.package(url: "https://github.com/vapor/apns.git", from: "4.2.0"),
.package(url: "https://github.com/vapor-community/Zip.git", from: "2.2.3"),
.package(url: "https://github.com/vapor-community/Zip.git", from: "2.2.4"),
.package(url: "https://github.com/apple/swift-certificates.git", from: "1.6.1"),
// used in tests
.package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.8.0"),
Expand Down
3 changes: 1 addition & 2 deletions Sources/Orders/Orders.docc/Extensions/OrdersService.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

### Essentials

- ``generateOrderContent(for:on:)``
- ``build(order:on:)``
- ``register(migrations:)``

### Push Notifications

- ``sendPushNotifications(for:on:)``
- ``sendPushNotificationsForOrder(id:of:on:)``
14 changes: 8 additions & 6 deletions Sources/Orders/Orders.docc/GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ final class OrderDelegate: OrdersDelegate {

Next, initialize the ``OrdersService`` inside the `configure.swift` file.
This will implement all of the routes that Apple Wallet expects to exist on your server.
In the `signingFilesDirectory` you specify there must be the `WWDR.pem`, `certificate.pem` and `key.pem` files.
If they are named like that you're good to go, otherwise you have to specify the custom name.

> Tip: Obtaining the three certificates files could be a bit tricky. You could get some guidance from [this guide](https://github.com/alexandercerutti/passkit-generator/wiki/Generating-Certificates) and [this video](https://www.youtube.com/watch?v=rJZdPoXHtzI). Those guides are for Wallet passes, but the process is similar for Wallet orders.
Expand All @@ -164,7 +162,9 @@ public func configure(_ app: Application) async throws {
let ordersService = try OrdersService(
app: app,
delegate: orderDelegate,
signingFilesDirectory: "Certificates/Orders/"
pemWWDRCertificate: Environment.get("PEM_WWDR_CERTIFICATE")!,
pemCertificate: Environment.get("PEM_CERTIFICATE")!,
pemPrivateKey: Environment.get("PEM_PRIVATE_KEY")!
)
}
```
Expand Down Expand Up @@ -203,7 +203,9 @@ public func configure(_ app: Application) async throws {
>(
app: app,
delegate: orderDelegate,
signingFilesDirectory: "Certificates/Orders/"
pemWWDRCertificate: Environment.get("PEM_WWDR_CERTIFICATE")!,
pemCertificate: Environment.get("PEM_CERTIFICATE")!,
pemPrivateKey: Environment.get("PEM_PRIVATE_KEY")!
)
}
```
Expand Down Expand Up @@ -284,7 +286,7 @@ struct OrdersController: RouteCollection {

> Note: You'll have to register the `OrdersController` in the `configure.swift` file, in order to pass it the ``OrdersService`` object.
Then use the object inside your route handlers to generate the order bundle with the ``OrdersService/generateOrderContent(for:on:)`` method and distribute it with the "`application/vnd.apple.order`" MIME type.
Then use the object inside your route handlers to generate the order bundle with the ``OrdersService/build(order:on:)`` method and distribute it with the "`application/vnd.apple.order`" MIME type.

```swift
fileprivate func orderHandler(_ req: Request) async throws -> Response {
Expand All @@ -297,7 +299,7 @@ fileprivate func orderHandler(_ req: Request) async throws -> Response {
throw Abort(.notFound)
}

let bundle = try await ordersService.generateOrderContent(for: orderData.order, on: req.db)
let bundle = try await ordersService.build(order: orderData.order, on: req.db)
let body = Response.Body(data: bundle)
var headers = HTTPHeaders()
headers.add(name: .contentType, value: "application/vnd.apple.order")
Expand Down
4 changes: 0 additions & 4 deletions Sources/Orders/Orders.docc/Orders.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,3 @@ For information on Apple Wallet orders, see the [Apple Developer Documentation](
- ``OrderModel``
- ``OrdersRegistrationModel``
- ``OrderDataModel``

### Errors

- ``OrdersError``
15 changes: 0 additions & 15 deletions Sources/Orders/OrdersDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,6 @@ public protocol OrdersDelegate: AnyObject, Sendable {
/// - Returns: A URL path which points to the template data for the order.
func template<O: OrderModel>(for order: O, db: any Database) async throws -> String

/// Generates the SSL `signature` file.
///
/// If you need to implement custom S/Mime signing you can use this
/// method to do so. You must generate a detached DER signature of the `manifest.json` file.
///
/// - Parameter root: The location of the `manifest.json` and where to write the `signature` to.
/// - Returns: Return `true` if you generated a custom `signature`, otherwise `false`.
func generateSignatureFile(in root: URL) -> Bool

/// Encode the order into JSON.
///
/// This method should generate the entire order JSON. You are provided with
Expand All @@ -51,9 +42,3 @@ public protocol OrdersDelegate: AnyObject, Sendable {
order: O, db: any Database, encoder: JSONEncoder
) async throws -> Data
}

extension OrdersDelegate {
public func generateSignatureFile(in root: URL) -> Bool {
return false
}
}
74 changes: 0 additions & 74 deletions Sources/Orders/OrdersError.swift

This file was deleted.

48 changes: 18 additions & 30 deletions Sources/Orders/OrdersService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,34 @@ public final class OrdersService: Sendable {
/// - Parameters:
/// - app: The `Vapor.Application` to use in route handlers and APNs.
/// - delegate: The ``OrdersDelegate`` to use for order generation.
/// - signingFilesDirectory: The path of the directory where the signing files (`wwdrCertificate`, `pemCertificate`, `pemPrivateKey`) are located.
/// - wwdrCertificate: The name of Apple's WWDR.pem certificate as contained in `signingFilesDirectory` path. Defaults to `WWDR.pem`.
/// - pemCertificate: The name of the PEM Certificate for signing the pass as contained in `signingFilesDirectory` path. Defaults to `certificate.pem`.
/// - pemPrivateKey: The name of the PEM Certificate's private key for signing the pass as contained in `signingFilesDirectory` path. Defaults to `key.pem`.
/// - pemPrivateKeyPassword: The password to the private key file. If the key is not encrypted it must be `nil`. Defaults to `nil`.
/// - sslBinary: The location of the `openssl` command as a file path.
/// - pushRoutesMiddleware: The `Middleware` to use for push notification routes. If `nil`, push routes will not be registered.
/// - logger: The `Logger` to use.
/// - pemWWDRCertificate: Apple's WWDR.pem certificate in PEM format.
/// - pemCertificate: The PEM Certificate for signing orders.
/// - pemPrivateKey: The PEM Certificate's private key for signing orders.
/// - pemPrivateKeyPassword: The password to the private key. If the key is not encrypted it must be `nil`. Defaults to `nil`.
/// - openSSLPath: The location of the `openssl` command as a file path.
public init(
app: Application,
delegate: any OrdersDelegate,
signingFilesDirectory: String,
wwdrCertificate: String = "WWDR.pem",
pemCertificate: String = "certificate.pem",
pemPrivateKey: String = "key.pem",
pemPrivateKeyPassword: String? = nil,
sslBinary: String = "/usr/bin/openssl",
pushRoutesMiddleware: (any Middleware)? = nil,
logger: Logger? = nil
logger: Logger? = nil,
pemWWDRCertificate: String,
pemCertificate: String,
pemPrivateKey: String,
pemPrivateKeyPassword: String? = nil,
openSSLPath: String = "/usr/bin/openssl"
) throws {
self.service = try .init(
app: app,
delegate: delegate,
signingFilesDirectory: signingFilesDirectory,
wwdrCertificate: wwdrCertificate,
pushRoutesMiddleware: pushRoutesMiddleware,
logger: logger,
pemWWDRCertificate: pemWWDRCertificate,
pemCertificate: pemCertificate,
pemPrivateKey: pemPrivateKey,
pemPrivateKeyPassword: pemPrivateKeyPassword,
sslBinary: sslBinary,
pushRoutesMiddleware: pushRoutesMiddleware,
logger: logger
openSSLPath: openSSLPath
)
}

Expand All @@ -56,9 +53,10 @@ public final class OrdersService: Sendable {
/// - Parameters:
/// - order: The order to generate the content for.
/// - db: The `Database` to use.
///
/// - Returns: The generated order content.
public func generateOrderContent(for order: Order, on db: any Database) async throws -> Data {
try await service.generateOrderContent(for: order, on: db)
public func build(order: Order, on db: any Database) async throws -> Data {
try await service.build(order: order, on: db)
}

/// Adds the migrations for Wallet orders models.
Expand All @@ -71,16 +69,6 @@ public final class OrdersService: Sendable {
migrations.add(OrdersErrorLog())
}

/// Sends push notifications for a given order.
///
/// - Parameters:
/// - id: The `UUID` of the order to send the notifications for.
/// - typeIdentifier: The type identifier of the order.
/// - db: The `Database` to use.
public func sendPushNotificationsForOrder(id: UUID, of typeIdentifier: String, on db: any Database) async throws {
try await service.sendPushNotificationsForOrder(id: id, of: typeIdentifier, on: db)
}

/// Sends push notifications for a given order.
///
/// - Parameters:
Expand Down
Loading

0 comments on commit 61371c3

Please sign in to comment.