Skip to content

Commit 61371c3

Browse files
authored
Simplify signing and notifications APIs (#17)
* Test localization * Simplify signing * Simplify notifications API * Update DocC * Update Zip * Rename `openSSLURL` to `openSSLPath` * Unify error types
1 parent 53e9146 commit 61371c3

31 files changed

+590
-770
lines changed

.spi.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
version: 1
22
builder:
33
configs:
4-
- documentation_targets: [PassKit, Passes, Orders]
5-
swift_version: 6.0
4+
- documentation_targets: [PassKit, Passes, Orders]

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ let package = Package(
1414
.package(url: "https://github.com/vapor/vapor.git", from: "4.106.1"),
1515
.package(url: "https://github.com/vapor/fluent.git", from: "4.12.0"),
1616
.package(url: "https://github.com/vapor/apns.git", from: "4.2.0"),
17-
.package(url: "https://github.com/vapor-community/Zip.git", from: "2.2.3"),
17+
.package(url: "https://github.com/vapor-community/Zip.git", from: "2.2.4"),
1818
.package(url: "https://github.com/apple/swift-certificates.git", from: "1.6.1"),
1919
// used in tests
2020
.package(url: "https://github.com/vapor/fluent-sqlite-driver.git", from: "4.8.0"),

Sources/Orders/Orders.docc/Extensions/OrdersService.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
### Essentials
66

7-
- ``generateOrderContent(for:on:)``
7+
- ``build(order:on:)``
88
- ``register(migrations:)``
99

1010
### Push Notifications
1111

1212
- ``sendPushNotifications(for:on:)``
13-
- ``sendPushNotificationsForOrder(id:of:on:)``

Sources/Orders/Orders.docc/GettingStarted.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,6 @@ final class OrderDelegate: OrdersDelegate {
147147

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

153151
> 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.
154152
@@ -164,7 +162,9 @@ public func configure(_ app: Application) async throws {
164162
let ordersService = try OrdersService(
165163
app: app,
166164
delegate: orderDelegate,
167-
signingFilesDirectory: "Certificates/Orders/"
165+
pemWWDRCertificate: Environment.get("PEM_WWDR_CERTIFICATE")!,
166+
pemCertificate: Environment.get("PEM_CERTIFICATE")!,
167+
pemPrivateKey: Environment.get("PEM_PRIVATE_KEY")!
168168
)
169169
}
170170
```
@@ -203,7 +203,9 @@ public func configure(_ app: Application) async throws {
203203
>(
204204
app: app,
205205
delegate: orderDelegate,
206-
signingFilesDirectory: "Certificates/Orders/"
206+
pemWWDRCertificate: Environment.get("PEM_WWDR_CERTIFICATE")!,
207+
pemCertificate: Environment.get("PEM_CERTIFICATE")!,
208+
pemPrivateKey: Environment.get("PEM_PRIVATE_KEY")!
207209
)
208210
}
209211
```
@@ -284,7 +286,7 @@ struct OrdersController: RouteCollection {
284286

285287
> Note: You'll have to register the `OrdersController` in the `configure.swift` file, in order to pass it the ``OrdersService`` object.
286288
287-
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.
289+
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.
288290

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

300-
let bundle = try await ordersService.generateOrderContent(for: orderData.order, on: req.db)
302+
let bundle = try await ordersService.build(order: orderData.order, on: req.db)
301303
let body = Response.Body(data: bundle)
302304
var headers = HTTPHeaders()
303305
headers.add(name: .contentType, value: "application/vnd.apple.order")

Sources/Orders/Orders.docc/Orders.md

-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,3 @@ For information on Apple Wallet orders, see the [Apple Developer Documentation](
3434
- ``OrderModel``
3535
- ``OrdersRegistrationModel``
3636
- ``OrderDataModel``
37-
38-
### Errors
39-
40-
- ``OrdersError``

Sources/Orders/OrdersDelegate.swift

-15
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,6 @@ public protocol OrdersDelegate: AnyObject, Sendable {
2525
/// - Returns: A URL path which points to the template data for the order.
2626
func template<O: OrderModel>(for order: O, db: any Database) async throws -> String
2727

28-
/// Generates the SSL `signature` file.
29-
///
30-
/// If you need to implement custom S/Mime signing you can use this
31-
/// method to do so. You must generate a detached DER signature of the `manifest.json` file.
32-
///
33-
/// - Parameter root: The location of the `manifest.json` and where to write the `signature` to.
34-
/// - Returns: Return `true` if you generated a custom `signature`, otherwise `false`.
35-
func generateSignatureFile(in root: URL) -> Bool
36-
3728
/// Encode the order into JSON.
3829
///
3930
/// This method should generate the entire order JSON. You are provided with
@@ -51,9 +42,3 @@ public protocol OrdersDelegate: AnyObject, Sendable {
5142
order: O, db: any Database, encoder: JSONEncoder
5243
) async throws -> Data
5344
}
54-
55-
extension OrdersDelegate {
56-
public func generateSignatureFile(in root: URL) -> Bool {
57-
return false
58-
}
59-
}

Sources/Orders/OrdersError.swift

-74
This file was deleted.

Sources/Orders/OrdersService.swift

+18-30
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,34 @@ public final class OrdersService: Sendable {
1717
/// - Parameters:
1818
/// - app: The `Vapor.Application` to use in route handlers and APNs.
1919
/// - delegate: The ``OrdersDelegate`` to use for order generation.
20-
/// - signingFilesDirectory: The path of the directory where the signing files (`wwdrCertificate`, `pemCertificate`, `pemPrivateKey`) are located.
21-
/// - wwdrCertificate: The name of Apple's WWDR.pem certificate as contained in `signingFilesDirectory` path. Defaults to `WWDR.pem`.
22-
/// - pemCertificate: The name of the PEM Certificate for signing the pass as contained in `signingFilesDirectory` path. Defaults to `certificate.pem`.
23-
/// - pemPrivateKey: The name of the PEM Certificate's private key for signing the pass as contained in `signingFilesDirectory` path. Defaults to `key.pem`.
24-
/// - pemPrivateKeyPassword: The password to the private key file. If the key is not encrypted it must be `nil`. Defaults to `nil`.
25-
/// - sslBinary: The location of the `openssl` command as a file path.
2620
/// - pushRoutesMiddleware: The `Middleware` to use for push notification routes. If `nil`, push routes will not be registered.
2721
/// - logger: The `Logger` to use.
22+
/// - pemWWDRCertificate: Apple's WWDR.pem certificate in PEM format.
23+
/// - pemCertificate: The PEM Certificate for signing orders.
24+
/// - pemPrivateKey: The PEM Certificate's private key for signing orders.
25+
/// - pemPrivateKeyPassword: The password to the private key. If the key is not encrypted it must be `nil`. Defaults to `nil`.
26+
/// - openSSLPath: The location of the `openssl` command as a file path.
2827
public init(
2928
app: Application,
3029
delegate: any OrdersDelegate,
31-
signingFilesDirectory: String,
32-
wwdrCertificate: String = "WWDR.pem",
33-
pemCertificate: String = "certificate.pem",
34-
pemPrivateKey: String = "key.pem",
35-
pemPrivateKeyPassword: String? = nil,
36-
sslBinary: String = "/usr/bin/openssl",
3730
pushRoutesMiddleware: (any Middleware)? = nil,
38-
logger: Logger? = nil
31+
logger: Logger? = nil,
32+
pemWWDRCertificate: String,
33+
pemCertificate: String,
34+
pemPrivateKey: String,
35+
pemPrivateKeyPassword: String? = nil,
36+
openSSLPath: String = "/usr/bin/openssl"
3937
) throws {
4038
self.service = try .init(
4139
app: app,
4240
delegate: delegate,
43-
signingFilesDirectory: signingFilesDirectory,
44-
wwdrCertificate: wwdrCertificate,
41+
pushRoutesMiddleware: pushRoutesMiddleware,
42+
logger: logger,
43+
pemWWDRCertificate: pemWWDRCertificate,
4544
pemCertificate: pemCertificate,
4645
pemPrivateKey: pemPrivateKey,
4746
pemPrivateKeyPassword: pemPrivateKeyPassword,
48-
sslBinary: sslBinary,
49-
pushRoutesMiddleware: pushRoutesMiddleware,
50-
logger: logger
47+
openSSLPath: openSSLPath
5148
)
5249
}
5350

@@ -56,9 +53,10 @@ public final class OrdersService: Sendable {
5653
/// - Parameters:
5754
/// - order: The order to generate the content for.
5855
/// - db: The `Database` to use.
56+
///
5957
/// - Returns: The generated order content.
60-
public func generateOrderContent(for order: Order, on db: any Database) async throws -> Data {
61-
try await service.generateOrderContent(for: order, on: db)
58+
public func build(order: Order, on db: any Database) async throws -> Data {
59+
try await service.build(order: order, on: db)
6260
}
6361

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

74-
/// Sends push notifications for a given order.
75-
///
76-
/// - Parameters:
77-
/// - id: The `UUID` of the order to send the notifications for.
78-
/// - typeIdentifier: The type identifier of the order.
79-
/// - db: The `Database` to use.
80-
public func sendPushNotificationsForOrder(id: UUID, of typeIdentifier: String, on db: any Database) async throws {
81-
try await service.sendPushNotificationsForOrder(id: id, of: typeIdentifier, on: db)
82-
}
83-
8472
/// Sends push notifications for a given order.
8573
///
8674
/// - Parameters:

0 commit comments

Comments
 (0)