// // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // import Foundation public protocol DeviceProvisioningService { func requestDeviceProvisioningCode() -> Promise func provisionDevice(messageBody: Data, ephemeralDeviceId: String) -> Promise } public class DeviceProvisioningServiceImpl: DeviceProvisioningService { private let networkManager: NetworkManager private let schedulers: Schedulers public init(networkManager: NetworkManager, schedulers: Schedulers) { self.networkManager = networkManager self.schedulers = schedulers } public func requestDeviceProvisioningCode() -> Promise { let request = OWSRequestFactory.deviceProvisioningCode() return firstly(on: schedulers.sharedUserInitiated) { self.networkManager.makePromise(request: request, canUseWebSocket: true) }.map(on: schedulers.sharedUserInitiated) { (httpResponse: HTTPResponse) -> String in guard let httpResponseData = httpResponse.responseBodyData else { throw OWSAssertionError("Missing responseBodyData.") } let response = try JSONDecoder().decode(DeviceProvisioningCodeResponse.self, from: httpResponseData) guard let nonEmptyVerificationCode = response.verificationCode.nilIfEmpty else { throw OWSAssertionError("Empty verificationCode.") } return nonEmptyVerificationCode }.recover(on: schedulers.sharedUserInitiated) { (error: Error) -> Promise in throw DeviceLimitExceededError(error) ?? error } } private struct DeviceProvisioningCodeResponse: Decodable { var verificationCode: String } public func provisionDevice(messageBody: Data, ephemeralDeviceId: String) -> Promise { let request = OWSRequestFactory.provisionDevice( withMessageBody: messageBody, ephemeralDeviceId: ephemeralDeviceId ) return firstly(on: schedulers.sharedUserInitiated) { self.networkManager.makePromise(request: request, canUseWebSocket: true) .asVoid(on: self.schedulers.sync) }.recover(on: schedulers.sharedUserInitiated) { (error: Error) -> Promise in owsFailDebugUnlessNetworkFailure(error) throw error } } }