Add types and definitions

This commit is contained in:
Christoph Hagen 2022-06-05 11:47:58 +02:00
parent 4114ad1227
commit 38467c742c
7 changed files with 301 additions and 0 deletions

View File

@ -0,0 +1,21 @@
import Foundation
/**
A push message to send to the push server.
This structure contains the content of the notification, as well as all data to send the notification to one or more recipients.
The message contains the authorization of the sender as well.
*/
struct AuthenticatedPushMessage {
/// The device sending the message
let sender: DeviceAuthentication
/// The message to send
let message: PushMessage
}
extension AuthenticatedPushMessage: Codable {
}

View File

@ -0,0 +1,26 @@
import Foundation
/**
An object to store the necessary information to authenticate a device to the server.
*/
struct DeviceAuthentication {
/**
The push token of the device.
The token is used to uniquely identify the device.
*/
let pushToken: PushToken
/**
The authentication token of the device.
This token is created by the server during device registration, and used for all subsequent requests.
*/
let authentication: AuthenticationToken
}
extension DeviceAuthentication: Codable {
}

View File

@ -0,0 +1,19 @@
import Foundation
/**
A statement from the administrator to approve or reject a device for an application.
- Note: There is a potential security risk here: Capturing this message and retransmitting it to the `confirm` route can approve previously rejected devices if they register again with the same push token. A timestamp, counter, or nonce can prevent this.
*/
struct DeviceDecision {
/// The push token of the approved or rejected device.
let pushToken: PushToken
/// The hash of the master key to authenticate the request.
let masterKeyHash: Data
}
extension DeviceDecision: Codable {
}

View File

@ -0,0 +1,24 @@
import Foundation
/**
An object containing the information required to issue a registration request to the server.
*/
struct DeviceRegistration {
/// The push token of the registering device
let pushToken: PushToken
/// The application id for which the device wants to register
let application: ApplicationId
/**
A custom name for the device.
The name is displayed when registered users request a list of all devices in an application.
*/
let name: String
}
extension DeviceRegistration: Codable {
}

View File

@ -0,0 +1,17 @@
import Foundation
/**
An object to update the push token of a device.
*/
struct PushTokenUpdate {
/// The authentication of the requesting device.
let device: DeviceAuthentication
/// The new push token to register
let newToken: PushToken
}
extension PushTokenUpdate: Codable {
}

127
Sources/Push-API/Push.swift Normal file
View File

@ -0,0 +1,127 @@
import Foundation
/**
All routes available on the server.
The raw values of the cases represent the path to the route.
*/
enum Route: String {
/**
Register a device for push notifications.
If the selected application requires approval, then the administrator must approve the device before it can receive push notifications.
* HTTP Method: `POST`
* HTTP Body: `DeviceRegistration` JSON object.
* Response: The binary authentication token generated for the device. Status `417`, if the application does not exist.
*/
case registerNewDevice = "register"
/**
Update the push token for a registered device.
* HTTP Method: `POST`
* HTTP Body: A `PushTokenUpdate` JSON object.
* Response: A status of `200` is returned on success. `401` if the authorization fails.
*/
case updatePushToken = "update"
/**
Get a list of unapproved devices for review.
* HTTP Method: `POST`
* HTTP Body: The binary SHA256 hash of the master key using the custom salt
* Response: An array of `DeviceRegistration` elements encoded in JSON. `401` if the master key is incorrect.
*/
case listUnapprovedDevices = "check"
/**
Get a list of approved devices for the same application as the requestor.
* HTTP Method: `POST`
* HTTP Body: A `DeviceConfirmation` JSON object
* Response: An array of `DeviceRegistration` with all devices registered for the same application. Status `401` if the authentication is incorrect. Status `417`, if the application does not allow device listing.
*/
case listDevicesInApplication = "devices"
/**
Approve a device for an application.
* HTTP Method: `POST`
* HTTP Body: A `DeviceDecision` object with the push token of the approved device and the SHA256 hash of the master key.
* Response: Status `200` on success, `401` for an invalid master key.
- Note: If no device with the push token exists, then this call does nothing and returns `200`
*/
case approveDevice = "approve"
/**
Reject a device.
* HTTP Method: `POST`
* HTTP Body: A `DeviceDecision` object with the push token of the rejected device and the SHA256 hash of the master key.
* Response: Status `200` on success, `401` for an invalid master key.
- Note: If no device with the push token exists, then this call does nothing and returns `200`
*/
case rejectDevice = "reject"
/**
Check if a registered device is approved for usage.
* HTTP Method: `POST`
* HTTP Body: A `DeviceAuthentication` object
* Response: Status `200` if the device is confirmed, and `401` if the device is not confirmed.
*/
case isDeviceApproved = "approved"
/**
Send a push notification to a list of devices.
* HTTP Method: `POST`
* HTTP Body: An `AuthenticatedPushMessage` object
* Response: `200` on success, `401` if authentication is invalid.
*/
case sendPushNotification = "push"
/// The HTTP method required for the route.
var httpMethod: String {
// Currently all routes expect `POST` requests.
return "POST"
}
/**
Create the url for the route on a server.
- Parameter server: The url of the server.
- Returns: The url to the route.
*/
func url(for server: URL) -> URL {
server.appendingPathComponent(rawValue)
}
}
/**
An apple push token (usually 32 byte).
Push tokens are created when a device registers with the Apple Push Notification Service (APNS). The tokens act as identifiers to transmit push notifications to devices. The server uses the unique push tokens to identify devices and assign them to applications.
*/
typealias PushToken = Data
/**
An authentication token of a device.
These tokens are created by the server during device registration, and used for all subsequent requests in combination with the push token.
*/
typealias AuthenticationToken = Data
/**
The name of an application.
The push server can simultaneously handle multiple applications, which are identified by a unique string. Applications can require confirmation of new device registrations by the administrator. The server configuration also specifies if applications allow the retrieval of device lists for all registered devices, to directly send push notifications to the participants.
*/
typealias ApplicationId = String
/**
The SHA256 hash of the master key with a salt.
*/
typealias MasterKeyHash = Data

View File

@ -0,0 +1,67 @@
import APNSwift
import Foundation
/**
A push message to send to other devices.
This structure contains the content of the notification, as well as all data to send the notification to one or more recipients.
*/
struct PushMessage {
/**
A list of push tokens for all recipients of the message
*/
let recipients: [PushToken]
/**
The notification content.
*/
let payload: APNSwiftPayload
/**
The value of this header must accurately reflect the contents of your notifications payload.
If theres a mismatch, or if the header is missing on required systems, APNs may return an error, delay the delivery of the notification, or drop it altogether.
- Note: Required for watchOS 6 and later; recommended for macOS, iOS, tvOS, and iPadOS
*/
let pushType: APNSwiftConnection.PushType
/**
The date at which the notification is no longer valid.
If the value is not `nil`, APNs stores the notification and tries to deliver it at least once, repeating the attempt as needed until the specified date. If the value is `nil`, APNs attempts to deliver the notification only once and doesnt store it.
A single APNs attempt may involve retries over multiple network interfaces and connections of the destination device. Often these retries span over some time period, depending on the network characteristics. In addition, a push notification may take some time on the network after APNs sends it to the device. APNs uses best efforts to honor the expiry date without any guarantee. If the value is not `nil`, the notification may be delivered after the mentioned date. If the value is `nil`, the notification may be delivered with some delay.
*/
let expiration: Date?
/**
The priority of the notification.
Set `lowPriority = false` to send the notification immediately.
Set `lowPriority = true` to send the notification based on power considerations on the users device.
*/
let lowPriority: Bool
/**
An identifier you use to coalesce multiple notifications into a single notification for the user.
Typically, each notification request causes a new notification to be displayed on the users device. When sending the same notification more than once, use the same value in this header to coalesce the requests. The value of this key must not exceed 64 bytes.
*/
let collapseIdentifier: String?
/**
The topic for the notification.
In general, the topic is your apps bundle ID/app ID. It can have a suffix based on the type of push notification. If youre using a certificate that supports PushKit VoIP or watchOS complication notifications, you must include this header with bundle ID of you app and if applicable, the proper suffix. If youre using token-based authentication with APNs, you must include this header with the correct bundle ID and suffix combination. To learn more about app ID, see [Register an App ID](https://help.apple.com/developer-account/#/dev1b35d6f83).
*/
let topic: String?
}
extension PushMessage: Codable {
}
extension APNSwiftConnection.PushType: Codable {
}