diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index af981e4e30..8c4ced00d7 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -886,6 +886,7 @@ public enum CollectibleItemInfoScreenSubject { public protocol SharedAccountContext: AnyObject { var sharedContainerPath: String { get } var basePath: String { get } + var networkArguments: NetworkInitializationArguments { get } var mainWindow: Window1? { get } var accountManager: AccountManager { get } var appLockContext: AppLockContext { get } diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift index f829177087..59c2896d0c 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift @@ -229,7 +229,13 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin |> take(1) |> mapToSignal { _ -> Signal in return Signal { subscriber in - return context.engine.accountData.requestNextChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber, phoneCodeHash: data.hash).start(next: { next in + return context.engine.accountData.requestNextChangeAccountPhoneNumberVerification( + phoneNumber: phoneNumber, + phoneCodeHash: data.hash, + apiId: context.sharedContext.networkArguments.apiId, + apiHash: context.sharedContext.networkArguments.apiHash, + firebaseSecretStream: context.sharedContext.firebaseSecretStream + ).start(next: { next in currentDataPromise?.set(.single(next)) }, error: { error in diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift index 7e9b78957d..12a535cc9d 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift @@ -36,7 +36,13 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll authorizationPushConfiguration |> castError(RequestChangeAccountPhoneNumberVerificationError.self) |> mapToSignal { authorizationPushConfiguration in - return context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber, pushNotificationConfiguration: authorizationPushConfiguration, firebaseSecretStream: context.sharedContext.firebaseSecretStream) + return context.engine.accountData.requestChangeAccountPhoneNumberVerification( + apiId: context.sharedContext.networkArguments.apiId, + apiHash: context.sharedContext.networkArguments.apiHash, + phoneNumber: phoneNumber, + pushNotificationConfiguration: authorizationPushConfiguration, + firebaseSecretStream: context.sharedContext.firebaseSecretStream + ) } |> deliverOnMainQueue).start(next: { [weak controller] next in controller?.inProgress = false diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 47b5dfce0d..ee429ff014 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -129,11 +129,10 @@ enum SendFirebaseAuthorizationCodeError { case generic } -private func sendFirebaseAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, phoneCodeHash: String, timeout: Int32?, firebaseSecret: String, syncContacts: Bool) -> Signal { - //auth.requestFirebaseSms#89464b50 flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string ios_push_secret:flags.1?string = Bool; +func sendFirebaseAuthorizationCode(network: Network, phoneNumber: String, apiId: Int32, apiHash: String, phoneCodeHash: String, timeout: Int32?, firebaseSecret: String) -> Signal { var flags: Int32 = 0 flags |= 1 << 1 - return account.network.request(Api.functions.auth.requestFirebaseSms(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, safetyNetToken: nil, playIntegrityToken: nil, iosPushSecret: firebaseSecret)) + return network.request(Api.functions.auth.requestFirebaseSms(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, safetyNetToken: nil, playIntegrityToken: nil, iosPushSecret: firebaseSecret)) |> mapError { _ -> SendFirebaseAuthorizationCodeError in return .generic } @@ -295,10 +294,10 @@ public func sendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) |> mapToSignal { firebaseSecret -> Signal in guard let firebaseSecret = firebaseSecret else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: phoneNumber, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: phoneNumber, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebasePushTimeout) } - return sendFirebaseAuthorizationCode(accountManager: accountManager, account: account, phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret, syncContacts: syncContacts) + return sendFirebaseAuthorizationCode(network: account.network, phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret) |> `catch` { _ -> Signal in return .single(false) } @@ -332,7 +331,7 @@ public func sendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) } else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: phoneNumber, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: phoneNumber, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebaseSendCodeError) } } } @@ -394,8 +393,20 @@ public func sendAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, number: String, apiId: Int32, apiHash: String, hash: String, syncContacts: Bool, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { - return account.network.request(Api.functions.auth.resendCode(flags: 0, phoneNumber: number, phoneCodeHash: hash, reason: nil), automaticFloodWait: false) +enum ResendAuthorizationCodeReason: String { + case firebasePushTimeout = "FIREBASE_PUSH_TIMEOUT" + case firebaseSendCodeError = "FIREBASE_SEND_CODE_ERROR" +} + +private func internalResendAuthorizationCode(accountManager: AccountManager, account: UnauthorizedAccount, number: String, apiId: Int32, apiHash: String, hash: String, syncContacts: Bool, firebaseSecretStream: Signal<[String: String], NoError>, reason: ResendAuthorizationCodeReason?) -> Signal { + var flags: Int32 = 0 + var mappedReason: String? + if let reason { + flags |= 1 << 0 + mappedReason = reason.rawValue + } + + return account.network.request(Api.functions.auth.resendCode(flags: flags, phoneNumber: number, phoneCodeHash: hash, reason: mappedReason), automaticFloodWait: false) |> mapError { error -> AuthorizationCodeRequestError in if error.errorDescription.hasPrefix("FLOOD_WAIT") { return .limitExceeded @@ -441,10 +452,10 @@ private func internalResendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) |> mapToSignal { firebaseSecret -> Signal in guard let firebaseSecret = firebaseSecret else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebasePushTimeout) } - return sendFirebaseAuthorizationCode(accountManager: accountManager, account: account, phoneNumber: number, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret, syncContacts: syncContacts) + return sendFirebaseAuthorizationCode(network: account.network, phoneNumber: number, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret) |> `catch` { _ -> Signal in return .single(false) } @@ -478,7 +489,7 @@ private func internalResendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) } else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebaseSendCodeError) } } } @@ -583,10 +594,10 @@ public func resendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) |> mapToSignal { firebaseSecret -> Signal in guard let firebaseSecret = firebaseSecret else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebasePushTimeout) } - return sendFirebaseAuthorizationCode(accountManager: accountManager, account: account, phoneNumber: number, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret, syncContacts: syncContacts) + return sendFirebaseAuthorizationCode(network: account.network, phoneNumber: number, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret) |> `catch` { _ -> Signal in return .single(false) } @@ -602,7 +613,7 @@ public func resendAuthorizationCode(accountManager: AccountManager castError(AuthorizationCodeRequestError.self) } else { - return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream) + return internalResendAuthorizationCode(accountManager: accountManager, account: account, number: number, apiId: apiId, apiHash: apiHash, hash: phoneCodeHash, syncContacts: syncContacts, firebaseSecretStream: firebaseSecretStream, reason: .firebaseSendCodeError) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift index c9acfde3c5..14e527f598 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift @@ -36,7 +36,7 @@ public enum RequestChangeAccountPhoneNumberVerificationError { case generic } -func _internal_requestChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { +func _internal_requestChangeAccountPhoneNumberVerification(account: Account, apiId: Int32, apiHash: String, phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { var flags: Int32 = 0 flags |= 1 << 5 //allowMissedCall @@ -66,20 +66,68 @@ func _internal_requestChangeAccountPhoneNumberVerification(account: Account, pho } |> mapToSignal { sentCode -> Signal in switch sentCode { - case let .sentCode(_, type, phoneCodeHash, nextType, timeout): + case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout): var parsedNextType: AuthorizationCodeNextType? if let nextType = nextType { parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)) + + if case let .sentCodeTypeFirebaseSms(_, _, _, receipt, pushTimeout, _) = type { + return firebaseSecretStream + |> map { mapping -> String? in + guard let receipt = receipt else { + return nil + } + if let value = mapping[receipt] { + return value + } + if receipt == "" && mapping.count == 1 { + return mapping.first?.value + } + return nil + } + |> filter { $0 != nil } + |> take(1) + |> timeout(Double(pushTimeout ?? 15), queue: .mainQueue(), alternate: .single(nil)) + |> castError(RequestChangeAccountPhoneNumberVerificationError.self) + |> mapToSignal { firebaseSecret -> Signal in + guard let firebaseSecret = firebaseSecret else { + return internalResendChangeAccountPhoneNumberVerification(account: account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream, reason: .firebasePushTimeout) + } + + return sendFirebaseAuthorizationCode(network: account.network, phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret) + |> `catch` { _ -> Signal in + return .single(false) + } + |> mapError { _ -> RequestChangeAccountPhoneNumberVerificationError in + return .generic + } + |> mapToSignal { success -> Signal in + if success { + return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType)) + } else { + return internalResendChangeAccountPhoneNumberVerification(account: account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream, reason: .firebaseSendCodeError) + } + } + } + } else { + return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType)) + } case .sentCodeSuccess: return .never() } } } -func _internal_requestNextChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, phoneCodeHash: String) -> Signal { - return account.network.request(Api.functions.auth.resendCode(flags: 0, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, reason: nil), automaticFloodWait: false) +private func internalResendChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, phoneCodeHash: String, apiId: Int32, apiHash: String, firebaseSecretStream: Signal<[String: String], NoError>, reason: ResendAuthorizationCodeReason?) -> Signal { + var flags: Int32 = 0 + var mappedReason: String? + if let reason { + flags |= 1 << 0 + mappedReason = reason.rawValue + } + + return account.network.request(Api.functions.auth.resendCode(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, reason: mappedReason), automaticFloodWait: false) |> mapError { error -> RequestChangeAccountPhoneNumberVerificationError in if error.errorDescription.hasPrefix("FLOOD_WAIT") { return .limitExceeded @@ -93,18 +141,63 @@ func _internal_requestNextChangeAccountPhoneNumberVerification(account: Account, } |> mapToSignal { sentCode -> Signal in switch sentCode { - case let .sentCode(_, type, phoneCodeHash, nextType, timeout): + case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout): var parsedNextType: AuthorizationCodeNextType? if let nextType = nextType { parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: timeout, nextType: parsedNextType)) + + if case let .sentCodeTypeFirebaseSms(_, _, _, receipt, pushTimeout, _) = type { + return firebaseSecretStream + |> map { mapping -> String? in + guard let receipt = receipt else { + return nil + } + if let value = mapping[receipt] { + return value + } + if receipt == "" && mapping.count == 1 { + return mapping.first?.value + } + return nil + } + |> filter { $0 != nil } + |> take(1) + |> timeout(Double(pushTimeout ?? 15), queue: .mainQueue(), alternate: .single(nil)) + |> castError(RequestChangeAccountPhoneNumberVerificationError.self) + |> mapToSignal { firebaseSecret -> Signal in + guard let firebaseSecret = firebaseSecret else { + return internalResendChangeAccountPhoneNumberVerification(account: account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream, reason: .firebasePushTimeout) + } + + return sendFirebaseAuthorizationCode(network: account.network, phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, phoneCodeHash: phoneCodeHash, timeout: codeTimeout, firebaseSecret: firebaseSecret) + |> `catch` { _ -> Signal in + return .single(false) + } + |> mapError { _ -> RequestChangeAccountPhoneNumberVerificationError in + return .generic + } + |> mapToSignal { success -> Signal in + if success { + return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType)) + } else { + return internalResendChangeAccountPhoneNumberVerification(account: account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream, reason: .firebaseSendCodeError) + } + } + } + } else { + return .single(ChangeAccountPhoneNumberData(type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType)) + } case .sentCodeSuccess: return .never() } } } +func _internal_requestNextChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, phoneCodeHash: String, apiId: Int32, apiHash: String, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { + return internalResendChangeAccountPhoneNumberVerification(account: account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream, reason: nil) +} + public enum ChangeAccountPhoneNumberError { case generic case invalidCode diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift index 9f48fc7460..02aa66b673 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift @@ -15,12 +15,12 @@ public extension TelegramEngine { return _internal_acceptTermsOfService(account: self.account, id: id) } - public func requestChangeAccountPhoneNumberVerification(phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { - return _internal_requestChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: phoneNumber, pushNotificationConfiguration: pushNotificationConfiguration, firebaseSecretStream: firebaseSecretStream) + public func requestChangeAccountPhoneNumberVerification(apiId: Int32, apiHash: String, phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { + return _internal_requestChangeAccountPhoneNumberVerification(account: self.account, apiId: apiId, apiHash: apiHash, phoneNumber: phoneNumber, pushNotificationConfiguration: pushNotificationConfiguration, firebaseSecretStream: firebaseSecretStream) } - public func requestNextChangeAccountPhoneNumberVerification(phoneNumber: String, phoneCodeHash: String) -> Signal { - return _internal_requestNextChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash) + public func requestNextChangeAccountPhoneNumberVerification(phoneNumber: String, phoneCodeHash: String, apiId: Int32, apiHash: String, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { + return _internal_requestNextChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, apiId: apiId, apiHash: apiHash, firebaseSecretStream: firebaseSecretStream) } public func requestChangeAccountPhoneNumber(phoneNumber: String, phoneCodeHash: String, phoneCode: String) -> Signal { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 698c5b2d12..6180c06fff 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -100,6 +100,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { public let applicationBindings: TelegramApplicationBindings public let sharedContainerPath: String public let basePath: String + public let networkArguments: NetworkInitializationArguments public let accountManager: AccountManager public let appLockContext: AppLockContext public var notificationController: NotificationContainerController? { @@ -253,6 +254,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { self.applicationBindings = applicationBindings self.sharedContainerPath = sharedContainerPath self.basePath = basePath + self.networkArguments = networkArguments self.accountManager = accountManager self.navigateToChatImpl = navigateToChat self.displayUpgradeProgress = displayUpgradeProgress