Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
signalapp
GitHub Repository: signalapp/Signal-iOS
Path: blob/main/Signal/Provisioning/ProvisioningCoordinatorImpl+Service.swift
1 views
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
import SignalServiceKit

extension ProvisioningCoordinatorImpl {

    enum Service {

        enum VerifySecondaryDeviceResponse {
            case success(ProvisioningServiceResponses.VerifySecondaryDeviceResponse)
            case obsoleteLinkedDevice
            case deviceLimitExceeded(DeviceLimitExceededError)
            case genericError(Error)
        }

        static func makeVerifySecondaryDeviceRequest(
            verificationCode: String,
            phoneNumber: String,
            authPassword: String,
            accountAttributes: AccountAttributes,
            apnRegistrationId: RegistrationRequestFactory.ApnRegistrationId?,
            prekeyBundles: RegistrationPreKeyUploadBundles,
            signalService: OWSSignalServiceProtocol,
        ) async -> VerifySecondaryDeviceResponse {
            let request = ProvisioningRequestFactory.verifySecondaryDeviceRequest(
                verificationCode: verificationCode,
                phoneNumber: phoneNumber,
                authPassword: authPassword,
                attributes: accountAttributes,
                apnRegistrationId: apnRegistrationId,
                prekeyBundles: prekeyBundles,
            )

            do {
                let response = try await signalService.urlSessionForMainSignalService().performRequest(request)
                return handleVerifySecondaryDeviceResponse(
                    statusCode: response.responseStatusCode,
                    bodyData: response.responseBodyData,
                )
            } catch {
                if error.isNetworkFailureOrTimeout {
                    return .genericError(error)
                }
                guard let error = error as? OWSHTTPError else {
                    return .genericError(error)
                }
                return handleVerifySecondaryDeviceResponse(
                    statusCode: error.responseStatusCode,
                    bodyData: error.httpResponseData,
                )
            }
        }

        private static func handleVerifySecondaryDeviceResponse(
            statusCode: Int,
            bodyData: Data?,
        ) -> VerifySecondaryDeviceResponse {
            let statusCode = ProvisioningServiceResponses.VerifySecondaryDeviceResponseCodes(rawValue: statusCode)
            switch statusCode {
            case .success:
                guard let bodyData else {
                    return .genericError(OWSAssertionError("Got empty verify secondary device response"))
                }
                guard
                    let response = try? JSONDecoder().decode(
                        ProvisioningServiceResponses.VerifySecondaryDeviceResponse.self,
                        from: bodyData,
                    )
                else {
                    return .genericError(OWSAssertionError("Unable to parse verify secondary device response from response"))
                }

                return .success(response)
            case .obsoleteLinkedDevice:
                Logger.warn("Obsolete linked device response")
                return .obsoleteLinkedDevice
            case .deviceLimitExceeded:
                Logger.warn("Device limit exceeded")
                return .deviceLimitExceeded(DeviceLimitExceededError())
            case .none, .unexpectedError:
                return .genericError(OWSAssertionError("Unknown status code"))
            }
        }

        static func makeUpdateSecondaryDeviceCapabilitiesRequest(
            capabilities: AccountAttributes.Capabilities,
            auth: ChatServiceAuth,
            networkManager: any NetworkManagerProtocol,
            tsAccountManager: TSAccountManager,
        ) async throws {
            let request = AccountAttributesRequestFactory(
                tsAccountManager: tsAccountManager,
            ).updateLinkedDeviceCapabilitiesRequest(
                capabilities,
                auth: auth,
            )

            // Don't care what the response is.
            _ = try await networkManager.asyncRequest(request)
        }
    }
}