sdk/communication/AzureCommunicationChat/Source/PushNotification/PushNotificationClient.swift (115 lines of code) (raw):

// -------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // The MIT License (MIT) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the ""Software""), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // // -------------------------------------------------------------------------- import AzureCommunicationCommon import AzureCore import Foundation /// ChatClient class for ChatThread operations. internal class PushNotificationClient { // MARK: Properties private let credential: CommunicationTokenCredential private let options: AzureCommunicationChatClientOptions private var registrarClient: RegistrarClient? internal var registrationId: String internal var deviceRegistrationToken: String internal var pushNotificationsStarted: Bool private var aesKey: String private var authKey: String private static let cryptoMethod: String = "0x70" // MARK: Initializers internal init( credential: CommunicationTokenCredential, options: AzureCommunicationChatClientOptions, registrationId: String ) { self.credential = credential self.options = options self.registrarClient = nil self.registrationId = registrationId self.deviceRegistrationToken = "" self.pushNotificationsStarted = false self.aesKey = "" self.authKey = "" } internal func startPushNotifications( deviceRegistrationToken: String, encryptionKey: String, completionHandler: @escaping (Result<HTTPResponse?, AzureError>) -> Void ) { self.deviceRegistrationToken = deviceRegistrationToken // Create RegistrarClient createRegistrarClient( credential: credential, options: options, registrationId: registrationId, completionHandler: { result in switch result { case let .success(createdRegistrarClient): do { // Generate and persist encryption key /* We require the Contoso to pass in a 512-bit key. Need to split it into two 256-bit keys, taking the first part for decrytion and the second part for authorization. */ if encryptionKey != "" { let encryptionKeys = try splitEncryptionKey(encryptionKey: encryptionKey) self.aesKey = encryptionKeys[0] self.authKey = encryptionKeys[1] } else { // If the Contoso doesn't want to implement encryption and we get an empty encrytionKey, we // just register two fake values. Encryption keys are required for a successful // registration. self.aesKey = "0000000000000000B00000000000000000000000AES=" self.authKey = "0000000000000000B0000000000000000000000AUTH=" } // Create RegistrarClientDescription (It should match valid APNS templates) let clientDescription = RegistrarClientDescription( aesKey: self.aesKey, authKey: self.authKey, cryptoMethod: PushNotificationClient.cryptoMethod ) // Create RegistrarTransportSettings (Path is device token) let transport = RegistrarTransportSettings( path: self.deviceRegistrationToken ) // Register for push notifications self.registrarClient = createdRegistrarClient guard let registrarClient = self.registrarClient else { completionHandler(.failure( AzureError .client("Failed to start push notifications. RegistrarClient is nil.") )) return } registrarClient.setRegistration(with: clientDescription, for: [transport]) { result in switch result { case let .success(response): self.pushNotificationsStarted = true completionHandler(.success(response)) case let .failure(error): self.options.logger .error( "Failed to start push notifications with error: \(error.localizedDescription)" ) completionHandler(.failure( AzureError .client("Failed to start push notifications", error) )) } } } catch { completionHandler(.failure(AzureError.client("Failed to split the encryption key: ", error))) } case let .failure(error): completionHandler(.failure(AzureError.client("Failed to initialize the RegistrarClient.", error))) } } ) } internal func stopPushNotifications( completionHandler: @escaping (Result<HTTPResponse?, AzureError>) -> Void ) { guard let registrarClient = registrarClient else { completionHandler(.failure( AzureError .client( "RegistrarClient is not initialized, cannot stop push notificaitons. Ensure startPushNotifications() is called first." ) )) return } registrarClient.deleteRegistration { result in switch result { case let .success(response): self.pushNotificationsStarted = false completionHandler(.success(response)) case let .failure(error): self.options.logger .error("Failed to stop push notifications with error: \(error.localizedDescription)") completionHandler(.failure(AzureError.client("Failed to stop push notifications", error))) } } } }