From 01ed96e83971b3ef148467b9f52c91d4f3838cac Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 14 Aug 2018 12:56:40 +0300 Subject: [PATCH] no message --- TelegramCore/Account.swift | 164 ++++-- TelegramCore/AccountManager.swift | 2 +- .../AccountStateManagementUtils.swift | 254 ++++----- TelegramCore/AccountViewTracker.swift | 19 +- TelegramCore/AddPeerMember.swift | 24 +- TelegramCore/Api0.swift | 21 +- TelegramCore/Api1.swift | 316 +++++++++-- TelegramCore/Api3.swift | 174 +++--- TelegramCore/BlockedPeers.swift | 2 +- TelegramCore/CallSessionManager.swift | 6 +- .../ChannelAdminEventLogContext.swift | 17 +- TelegramCore/ChannelAdminEventLogs.swift | 2 +- TelegramCore/ChannelAdmins.swift | 6 +- TelegramCore/ChannelCreation.swift | 2 +- .../ChannelHistoryAvailabilitySettings.swift | 45 +- TelegramCore/ChatContextResult.swift | 12 +- TelegramCore/ContactManagement.swift | 4 +- TelegramCore/CreateGroup.swift | 2 +- TelegramCore/DeepLinkInfo.swift | 5 +- .../DeleteMessagesInteractively.swift | 2 +- TelegramCore/Download.swift | 5 +- ...EarliestUnseenPersonalMentionMessage.swift | 6 + TelegramCore/EnqueueMessage.swift | 2 +- TelegramCore/ExportMessageLink.swift | 25 +- TelegramCore/FetchChatList.swift | 2 +- TelegramCore/FetchedMediaResource.swift | 18 +- TelegramCore/GrantSecureIdAccess.swift | 42 ++ TelegramCore/GroupsInCommon.swift | 18 +- TelegramCore/Holes.swift | 502 +++++++++--------- TelegramCore/ImportContact.swift | 24 +- TelegramCore/InstantPage.swift | 2 +- TelegramCore/JoinLink.swift | 108 ++-- TelegramCore/LoadMessagesIfNecessary.swift | 10 +- TelegramCore/LoadedPeerFromMessage.swift | 4 +- TelegramCore/LoadedStickerPack.swift | 2 +- TelegramCore/Localizations.swift | 2 +- ...anagedConsumePersonalMessagesActions.swift | 2 +- TelegramCore/ManagedDeviceContacts.swift | 28 +- ...ManagedLocalizationUpdatesOperations.swift | 27 +- .../ManagedSecretChatOutgoingOperations.swift | 258 ++++----- ...nizeConsumeMessageContentsOperations.swift | 4 +- TelegramCore/Network.swift | 2 +- TelegramCore/PeerAdmins.swift | 46 +- TelegramCore/PendingMessageManager.swift | 11 +- .../PendingMessageUploadedContent.swift | 4 +- ...ecretChatIncomingDecryptedOperations.swift | 1 - TelegramCore/RateCall.swift | 6 +- TelegramCore/RecentMediaItem.swift | 2 +- TelegramCore/RecentWebSessions.swift | 20 +- TelegramCore/RemovePeerChat.swift | 1 + TelegramCore/ReportPeer.swift | 20 +- .../RequestMessageActionCallback.swift | 40 +- TelegramCore/RequestSecureIdForm.swift | 49 +- TelegramCore/RequestUserPhotos.swift | 226 ++++---- TelegramCore/ResolvePeerByName.swift | 71 +-- TelegramCore/SaveSecureIdValue.swift | 57 +- TelegramCore/SavedStickerItem.swift | 2 +- TelegramCore/SearchMessages.swift | 35 +- TelegramCore/SearchPeers.swift | 143 ++--- TelegramCore/SearchStickers.swift | 45 +- .../SecureIdDriversLicenseValue.swift | 15 +- TelegramCore/SecureIdForm.swift | 11 +- TelegramCore/SecureIdIDCardValue.swift | 15 +- .../SecureIdInternalPassportValue.swift | 15 +- TelegramCore/SecureIdPassportValue.swift | 16 +- TelegramCore/SecureIdValue.swift | 6 +- TelegramCore/SecureIdValueContentError.swift | 20 + TelegramCore/Serialization.swift | 2 +- TelegramCore/StandaloneSendMessage.swift | 23 +- TelegramCore/StickerSetInstallation.swift | 16 +- TelegramCore/SupportPeerId.swift | 20 +- .../SynchronizeSavedStickersOperation.swift | 2 +- TelegramCore/TelegramMediaAction.swift | 6 +- TelegramCore/TelegramMediaContact.swift | 6 +- .../TelegramMediaExpiredContent.swift | 6 +- TelegramCore/TelegramMediaFile.swift | 42 +- TelegramCore/TelegramMediaGame.swift | 10 +- TelegramCore/TelegramMediaImage.swift | 36 +- TelegramCore/TelegramMediaInvoice.swift | 8 +- TelegramCore/TelegramMediaMap.swift | 6 +- TelegramCore/TelegramMediaWebDocument.swift | 6 +- TelegramCore/TelegramMediaWebpage.swift | 10 +- TelegramCore/TeleramMediaUnsupported.swift | 6 +- TelegramCore/TermsOfService.swift | 6 +- TelegramCore/ToggleChannelSignatures.swift | 4 +- TelegramCore/TwoStepVerification.swift | 48 +- .../UpdateGroupSpecificStickerset.swift | 34 +- TelegramCore/UpdateSecretChat.swift | 6 +- TelegramCore/WebpagePreview.swift | 2 +- 89 files changed, 2020 insertions(+), 1334 deletions(-) diff --git a/TelegramCore/Account.swift b/TelegramCore/Account.swift index bcdd7363c5..92713e2a00 100644 --- a/TelegramCore/Account.swift +++ b/TelegramCore/Account.swift @@ -350,14 +350,14 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id: public enum TwoStepPasswordDerivation { case unknown - case sha256_sha256_PBKDF2_HMAC_sha512(salt1: Data, salt2: Data, iterations: Int32) + case sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: Data, salt2: Data, iterations: Int32, g: Int32, p: Data) fileprivate init(_ apiAlgo: Api.PasswordKdfAlgo) { switch apiAlgo { case .passwordKdfAlgoUnknown: self = .unknown - case let .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(salt1, salt2): - self = .sha256_sha256_PBKDF2_HMAC_sha512(salt1: salt1.makeData(), salt2: salt2.makeData(), iterations: 100000) + case let .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1, salt2, g, p): + self = .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: salt1.makeData(), salt2: salt2.makeData(), iterations: 100000, g: g, p: p.makeData()) } } @@ -365,9 +365,9 @@ public enum TwoStepPasswordDerivation { switch self { case .unknown: return .passwordKdfAlgoUnknown - case let .sha256_sha256_PBKDF2_HMAC_sha512(salt1, salt2, iterations): + case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, g, p): precondition(iterations == 100000) - return .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(salt1: Buffer(data: salt1), salt2: Buffer(data: salt2)) + return .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: Buffer(data: salt1), salt2: Buffer(data: salt2), g: g, p: Buffer(data: p)) } } } @@ -401,9 +401,15 @@ public enum TwoStepSecurePasswordDerivation { } } +public struct TwoStepSRPSessionData { + public let id: Int64 + public let B: Data +} + public struct TwoStepAuthData { public let nextPasswordDerivation: TwoStepPasswordDerivation public let currentPasswordDerivation: TwoStepPasswordDerivation? + public let srpSessionData: TwoStepSRPSessionData? public let hasRecovery: Bool public let hasSecretValues: Bool public let currentHint: String? @@ -416,7 +422,7 @@ public func twoStepAuthData(_ network: Network) -> Signal map { config -> TwoStepAuthData in switch config { - case let .password(flags, currentAlgo, hint, emailUnconfirmedPattern, newAlgo, newSecureAlgo, secureRandom): + case let .password(flags, currentAlgo, srpB, srpId, hint, emailUnconfirmedPattern, newAlgo, newSecureAlgo, secureRandom): let hasRecovery = (flags & (1 << 0)) != 0 let hasSecureValues = (flags & (1 << 1)) != 0 @@ -432,7 +438,13 @@ public func twoStepAuthData(_ network: Network) -> Signal) -> Void in + var gValue = gValue + withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in + let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! + for i in 0 ..< 4 { + bytes.advanced(by: i).pointee = sourceBytes.advanced(by: 4 - i - 1).pointee + } + }) + } + + let pbkdfInnerData = sha256Digest(salt2 + sha256Digest(salt1 + passwordData + salt1) + salt2) + + guard let pbkdfResult = MTPBKDF2(pbkdfInnerData, salt1, iterations) else { return nil } - return (passwordHash, .sha256_sha256_PBKDF2_HMAC_sha512(salt1: nextSalt1, salt2: nextSalt2, iterations: iterations)) + + let x = sha256Digest(salt2 + pbkdfResult + salt2) + + let gx = MTExp(g, x, p)! + + return (gx, .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1: nextSalt1, salt2: nextSalt2, iterations: iterations, g: gValue, p: p)) } } -func passwordKDF(password: String, derivation: TwoStepPasswordDerivation) -> Data? { +struct PasswordKDFResult { + let id: Int64 + let A: Data + let M1: Data +} + +private func paddedToLength(what: Data, to: Data) -> Data { + if what.count < to.count { + var what = what + for _ in 0 ..< to.count - what.count { + what.insert(0, at: 0) + } + return what + } else { + return what + } +} + +private func paddedXor(_ a: Data, _ b: Data) -> Data { + let count = max(a.count, b.count) + var a = a + var b = b + while a.count < count { + a.insert(0, at: 0) + } + while b.count < count { + b.insert(0, at: 0) + } + a.withUnsafeMutableBytes { (aBytes: UnsafeMutablePointer) -> Void in + b.withUnsafeBytes { (bBytes: UnsafePointer) -> Void in + for i in 0 ..< count { + aBytes.advanced(by: i).pointee = aBytes.advanced(by: i).pointee ^ bBytes.advanced(by: i).pointee + } + } + } + return a +} + +func passwordKDF(password: String, derivation: TwoStepPasswordDerivation, srpSessionData: TwoStepSRPSessionData) -> PasswordKDFResult? { guard let passwordData = password.data(using: .utf8, allowLossyConversion: true) else { return nil } @@ -531,21 +589,51 @@ func passwordKDF(password: String, derivation: TwoStepPasswordDerivation) -> Dat switch derivation { case .unknown: return nil - case let .sha256_sha256_PBKDF2_HMAC_sha512(salt1, salt2, iterations): - var data = Data() - data.append(salt1) - data.append(passwordData) - data.append(salt1) - let firstHash = sha256Digest(data) - data = Data() - data.append(salt2) - data.append(firstHash) - data.append(salt2) - let secondHash = sha256Digest(data) - guard let passwordHash = MTPBKDF2(secondHash, salt1, iterations) else { + case let .sha256_sha256_PBKDF2_HMAC_sha512_sha256_srp(salt1, salt2, iterations, gValue, p): + var a = Data(count: p.count) + let aLength = a.count + a.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + let _ = SecRandomCopyBytes(nil, aLength, bytes) + } + + var g = Data(count: 4) + g.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + var gValue = gValue + withUnsafeBytes(of: &gValue, { (sourceBuffer: UnsafeRawBufferPointer) -> Void in + let sourceBytes = sourceBuffer.bindMemory(to: Int8.self).baseAddress! + for i in 0 ..< 4 { + bytes.advanced(by: i).pointee = sourceBytes.advanced(by: 4 - i - 1).pointee + } + }) + } + + let B = paddedToLength(what: srpSessionData.B, to: p) + let A = paddedToLength(what: MTExp(g, a, p)!, to: p) + let u = sha256Digest(A + B) + + // x = sha256(salt2 + pbkdf2(sha256(salt2 + sha256(salt1 + password + salt1) + salt2), salt1, 100000, sha512) + salt2) + let pbkdfInnerData = sha256Digest(salt2 + sha256Digest(salt1 + passwordData + salt1) + salt2) + + guard let pbkdfResult = MTPBKDF2(pbkdfInnerData, salt1, iterations) else { return nil } - return passwordHash + + let x = sha256Digest(salt2 + pbkdfResult + salt2) + + let gx = MTExp(g, x, p)! + + let k = sha256Digest(p + paddedToLength(what: g, to: p)) + + let s1 = MTModSub(B, MTModMul(k, gx, p)!, p)! + let s2 = MTAdd(a, MTMul(u, x)!)! + let S = MTExp(s1, s2, p)! + let K = sha256Digest(paddedToLength(what: S, to: p)) + let m1 = paddedXor(sha256Digest(p), sha256Digest(paddedToLength(what: g, to: p))) + let m2 = sha256Digest(salt1) + let m3 = sha256Digest(salt2) + let M = sha256Digest(m1 + m2 + m3 + A + B + K) + + return PasswordKDFResult(id: srpSessionData.id, A: A, M1: M) } } @@ -612,14 +700,14 @@ func securePasswordKDF(password: String, derivation: TwoStepSecurePasswordDeriva func verifyPassword(_ account: UnauthorizedAccount, password: String) -> Signal { return twoStepAuthData(account.network) |> mapToSignal { authData -> Signal in - guard let currentPasswordDerivation = authData.currentPasswordDerivation else { + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { return .fail(MTRpcError(errorCode: 400, errorDescription: "INTERNAL_NO_PASSWORD")) } - let currentPasswordHash = passwordKDF(password: password, derivation: currentPasswordDerivation) + let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) - if let currentPasswordHash = currentPasswordHash { - return account.network.request(Api.functions.auth.checkPassword(passwordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false) + if let kdfResult = kdfResult { + return account.network.request(Api.functions.auth.checkPassword(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false) } else { return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR")) } diff --git a/TelegramCore/AccountManager.swift b/TelegramCore/AccountManager.swift index 097c7618be..aa2c24e9ab 100644 --- a/TelegramCore/AccountManager.swift +++ b/TelegramCore/AccountManager.swift @@ -203,7 +203,7 @@ private func cleanupAccount(networkArguments: NetworkInitializationArguments, ac case let .authorized(account): account.shouldBeServiceTaskMaster.set(.single(.always)) return account.network.request(Api.functions.auth.logOut()) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(.boolFalse) } diff --git a/TelegramCore/AccountStateManagementUtils.swift b/TelegramCore/AccountStateManagementUtils.swift index 539735f914..dbb3e47f01 100644 --- a/TelegramCore/AccountStateManagementUtils.swift +++ b/TelegramCore/AccountStateManagementUtils.swift @@ -1356,140 +1356,140 @@ private func resetChannels(_ account: Account, peers: [Peer], state: AccountMuta } } return account.network.request(Api.functions.messages.getPeerDialogs(peers: inputPeers)) - |> map(Optional.init) - |> `catch` { error -> Signal in - if error.errorDescription == "CHANNEL_PRIVATE" && inputPeers.count == 1 { - return .single(nil) - } else { - return .single(nil) - } + |> map(Optional.init) + |> `catch` { error -> Signal in + if error.errorDescription == "CHANNEL_PRIVATE" && inputPeers.count == 1 { + return .single(nil) + } else { + return .single(nil) } - |> map { result -> AccountMutableState in - var updatedState = state - - var dialogsChats: [Api.Chat] = [] - var dialogsUsers: [Api.User] = [] - - var storeMessages: [StoreMessage] = [] - var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] - var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] - var channelStates: [PeerId: ChannelState] = [:] - var notificationSettings: [PeerId: PeerNotificationSettings] = [:] - - if let result = result { - switch result { - case let .peerDialogs(dialogs, messages, chats, users, _): - dialogsChats.append(contentsOf: chats) - dialogsUsers.append(contentsOf: users) - - loop: for dialog in dialogs { - let apiPeer: Api.Peer - let apiReadInboxMaxId: Int32 - let apiReadOutboxMaxId: Int32 - let apiTopMessage: Int32 - let apiUnreadCount: Int32 - let apiUnreadMentionsCount: Int32 - var apiChannelPts: Int32? - let apiNotificationSettings: Api.PeerNotifySettings - let apiMarkedUnread: Bool - switch dialog { - case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _): - apiPeer = peer - apiTopMessage = topMessage - apiReadInboxMaxId = readInboxMaxId - apiReadOutboxMaxId = readOutboxMaxId - apiUnreadCount = unreadCount - apiMarkedUnread = (flags & (1 << 3)) != 0 - apiUnreadMentionsCount = unreadMentionsCount - apiNotificationSettings = peerNotificationSettings - apiChannelPts = pts - /*feed*/ - /*case .dialogFeed: - assertionFailure() - continue loop*/ - } - - let peerId: PeerId - switch apiPeer { - case let .peerUser(userId): - peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) - case let .peerChat(chatId): - peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) - case let .peerChannel(channelId): - peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) - } - - if readStates[peerId] == nil { - readStates[peerId] = [:] - } - readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) - - if apiTopMessage != 0 { - mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage)) - } - - if let apiChannelPts = apiChannelPts { - channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts) - } - - notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) + } + |> map { result -> AccountMutableState in + var updatedState = state + + var dialogsChats: [Api.Chat] = [] + var dialogsUsers: [Api.User] = [] + + var storeMessages: [StoreMessage] = [] + var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:] + var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:] + var channelStates: [PeerId: ChannelState] = [:] + var notificationSettings: [PeerId: PeerNotificationSettings] = [:] + + if let result = result { + switch result { + case let .peerDialogs(dialogs, messages, chats, users, _): + dialogsChats.append(contentsOf: chats) + dialogsUsers.append(contentsOf: users) + + loop: for dialog in dialogs { + let apiPeer: Api.Peer + let apiReadInboxMaxId: Int32 + let apiReadOutboxMaxId: Int32 + let apiTopMessage: Int32 + let apiUnreadCount: Int32 + let apiUnreadMentionsCount: Int32 + var apiChannelPts: Int32? + let apiNotificationSettings: Api.PeerNotifySettings + let apiMarkedUnread: Bool + switch dialog { + case let .dialog(flags, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _): + apiPeer = peer + apiTopMessage = topMessage + apiReadInboxMaxId = readInboxMaxId + apiReadOutboxMaxId = readOutboxMaxId + apiUnreadCount = unreadCount + apiMarkedUnread = (flags & (1 << 3)) != 0 + apiUnreadMentionsCount = unreadMentionsCount + apiNotificationSettings = peerNotificationSettings + apiChannelPts = pts + /*feed*/ + /*case .dialogFeed: + assertionFailure() + continue loop*/ } - for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { - var updatedStoreMessage = storeMessage - if case let .Id(id) = storeMessage.id { - if let channelState = channelStates[id.peerId] { - var updatedAttributes = storeMessage.attributes - updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) - updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) - } - } - storeMessages.append(updatedStoreMessage) - } + let peerId: PeerId + switch apiPeer { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) } - } - } - - updatedState.mergeChats(dialogsChats) - updatedState.mergeUsers(dialogsUsers) - - for message in storeMessages { - if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud { - updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace) - } - } - - updatedState.addMessages(storeMessages, location: .UpperHistoryBlock) - - for (peerId, peerReadStates) in readStates { - for (namespace, state) in peerReadStates { - switch state { - case let .idBased(maxIncomingReadId, maxOutgoingReadId, maxKnownId, count, markedUnread): - updatedState.resetReadState(peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread) - default: - assertionFailure() - break + + if readStates[peerId] == nil { + readStates[peerId] = [:] + } + readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount, markedUnread: apiMarkedUnread) + + if apiTopMessage != 0 { + mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage)) + } + + if let apiChannelPts = apiChannelPts { + channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts) + } + + notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) } + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + var updatedStoreMessage = storeMessage + if case let .Id(id) = storeMessage.id { + if let channelState = channelStates[id.peerId] { + var updatedAttributes = storeMessage.attributes + updatedAttributes.append(ChannelMessageStateVersionAttribute(pts: channelState.pts)) + updatedStoreMessage = updatedStoreMessage.withUpdatedAttributes(updatedAttributes) + } + } + storeMessages.append(updatedStoreMessage) + } + } + } + } + + updatedState.mergeChats(dialogsChats) + updatedState.mergeUsers(dialogsUsers) + + for message in storeMessages { + if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud { + updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace) + } + } + + updatedState.addMessages(storeMessages, location: .UpperHistoryBlock) + + for (peerId, peerReadStates) in readStates { + for (namespace, state) in peerReadStates { + switch state { + case let .idBased(maxIncomingReadId, maxOutgoingReadId, maxKnownId, count, markedUnread): + updatedState.resetReadState(peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count, markedUnread: markedUnread) + default: + assertionFailure() + break } } - - for (peerId, tagSummary) in mentionTagSummaries { - updatedState.resetMessageTagSummary(peerId, namespace: Namespaces.Message.Cloud, count: tagSummary.count, range: tagSummary.range) - } - - for (peerId, channelState) in channelStates { - updatedState.updateChannelState(peerId, state: channelState) - } - - for (peerId, settings) in notificationSettings { - updatedState.updateNotificationSettings(.peer(peerId), notificationSettings: settings) - } - - // TODO: delete messages later than top - - return updatedState } + + for (peerId, tagSummary) in mentionTagSummaries { + updatedState.resetMessageTagSummary(peerId, namespace: Namespaces.Message.Cloud, count: tagSummary.count, range: tagSummary.range) + } + + for (peerId, channelState) in channelStates { + updatedState.updateChannelState(peerId, state: channelState) + } + + for (peerId, settings) in notificationSettings { + updatedState.updateNotificationSettings(.peer(peerId), notificationSettings: settings) + } + + // TODO: delete messages later than top + + return updatedState + } } private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableState) -> Signal<(AccountMutableState, Bool, Int32?), NoError> { @@ -1505,7 +1505,7 @@ private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableSt pollPts = 1 } return (account.network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: pollPts, limit: limit)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { error -> Signal in if error.errorDescription == "CHANNEL_PRIVATE" { return .single(nil) diff --git a/TelegramCore/AccountViewTracker.swift b/TelegramCore/AccountViewTracker.swift index a628d51218..c2218259ff 100644 --- a/TelegramCore/AccountViewTracker.swift +++ b/TelegramCore/AccountViewTracker.swift @@ -408,7 +408,7 @@ public final class AccountViewTracker { let signal = (account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { return account.network.request(Api.functions.messages.getMessagesViews(peer: inputPeer, id: messageIds.map { $0.id }, increment: .boolTrue)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal<[Int32]?, NoError> in return .single(nil) } @@ -525,6 +525,23 @@ public final class AccountViewTracker { } } + func forceUpdateCachedPeerData(peerId: PeerId) { + self.queue.async { + let context: PeerCachedDataContext + var dataUpdated = false + if let existingContext = self.cachedDataContexts[peerId] { + context = existingContext + } else { + context = PeerCachedDataContext() + self.cachedDataContexts[peerId] = context + } + context.timestamp = CFAbsoluteTimeGetCurrent() + if let account = self.account { + context.disposable.set(combineLatest(fetchAndUpdateSupplementalCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox), fetchAndUpdateCachedPeerData(peerId: peerId, network: account.network, postbox: account.postbox)).start()) + } + } + } + private func updateCachedPeerData(peerId: PeerId, viewId: Int32, referenceData: CachedPeerData?) { self.queue.async { let context: PeerCachedDataContext diff --git a/TelegramCore/AddPeerMember.swift b/TelegramCore/AddPeerMember.swift index 17d2485d11..ffab35ba31 100644 --- a/TelegramCore/AddPeerMember.swift +++ b/TelegramCore/AddPeerMember.swift @@ -177,11 +177,10 @@ public func addChannelMember(account: Account, peerId: PeerId, memberId: PeerId) } } -public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal { - return account.postbox.transaction { transaction -> Signal in - - var memberPeerIds:[PeerId:Peer] = [:] - var inputUsers:[Api.InputUser] = [] +public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [PeerId]) -> Signal { + return account.postbox.transaction { transaction -> Signal in + var memberPeerIds: [PeerId:Peer] = [:] + var inputUsers: [Api.InputUser] = [] for memberId in memberIds { if let peer = transaction.getPeer(memberId) { memberPeerIds[peerId] = peer @@ -193,14 +192,15 @@ public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [Peer if let peer = transaction.getPeer(peerId), let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { return account.network.request(Api.functions.channels.inviteToChannel(channel: inputChannel, users: inputUsers)) - |> retryRequest - |> mapToSignal { result -> Signal in - account.stateManager.addUpdates(result) - return fetchAndUpdateCachedParticipants(peerId: peerId, network:account.network, postbox: account.postbox) + |> retryRequest + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + account.viewTracker.forceUpdateCachedPeerData(peerId: peerId) + return .complete() } } else { - return .fail(Void()) + return .complete() } - - } |> switchToLatest + } + |> switchToLatest } diff --git a/TelegramCore/Api0.swift b/TelegramCore/Api0.swift index 91fc0bd915..df60cef4e3 100644 --- a/TelegramCore/Api0.swift +++ b/TelegramCore/Api0.swift @@ -43,6 +43,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-283684427] = { return Api.PageBlock.parse_pageBlockChannel($0) } dict[834148991] = { return Api.PageBlock.parse_pageBlockAudio($0) } dict[-614138572] = { return Api.account.TmpPassword.parse_tmpPassword($0) } + dict[-2103600678] = { return Api.SecureRequiredType.parse_secureRequiredType($0) } + dict[41187252] = { return Api.SecureRequiredType.parse_secureRequiredTypeOneOf($0) } dict[590459437] = { return Api.Photo.parse_photoEmpty($0) } dict[-1673036328] = { return Api.Photo.parse_photo($0) } dict[-1683826688] = { return Api.Chat.parse_chatEmpty($0) } @@ -81,6 +83,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } dict[-791039645] = { return Api.channels.ChannelParticipant.parse_channelParticipant($0) } + dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) } + dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) } dict[-1432995067] = { return Api.storage.FileType.parse_fileUnknown($0) } dict[1086091090] = { return Api.storage.FileType.parse_filePartial($0) } dict[8322574] = { return Api.storage.FileType.parse_fileJpeg($0) } @@ -334,7 +338,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) } dict[-886477832] = { return Api.LabeledPrice.parse_labeledPrice($0) } dict[-438840932] = { return Api.messages.ChatFull.parse_chatFull($0) } - dict[108557032] = { return Api.InputSecureValue.parse_inputSecureValue($0) } + dict[-618540889] = { return Api.InputSecureValue.parse_inputSecureValue($0) } dict[1722786150] = { return Api.help.DeepLinkInfo.parse_deepLinkInfoEmpty($0) } dict[1783556146] = { return Api.help.DeepLinkInfo.parse_deepLinkInfo($0) } dict[-313079300] = { return Api.account.WebAuthorizations.parse_webAuthorizations($0) } @@ -356,6 +360,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-449327402] = { return Api.SecureValueError.parse_secureValueErrorSelfie($0) } dict[2054162547] = { return Api.SecureValueError.parse_secureValueErrorFile($0) } dict[1717706985] = { return Api.SecureValueError.parse_secureValueErrorFiles($0) } + dict[-2036501105] = { return Api.SecureValueError.parse_secureValueError($0) } + dict[-1592506512] = { return Api.SecureValueError.parse_secureValueErrorTranslationFile($0) } + dict[878931416] = { return Api.SecureValueError.parse_secureValueErrorTranslationFiles($0) } dict[1489977929] = { return Api.ChannelBannedRights.parse_channelBannedRights($0) } dict[-1613493288] = { return Api.NotifyPeer.parse_notifyPeer($0) } dict[-1261946036] = { return Api.NotifyPeer.parse_notifyUsers($0) } @@ -371,7 +378,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1493171408] = { return Api.HighScore.parse_highScore($0) } dict[-305282981] = { return Api.TopPeer.parse_topPeer($0) } dict[986597452] = { return Api.contacts.Link.parse_link($0) } - dict[-1263225191] = { return Api.SecureValue.parse_secureValue($0) } + dict[411017418] = { return Api.SecureValue.parse_secureValue($0) } dict[-316748368] = { return Api.SecureValueHash.parse_secureValueHash($0) } dict[1444661369] = { return Api.ContactBlocked.parse_contactBlocked($0) } dict[-2128698738] = { return Api.auth.CheckedPhone.parse_checkedPhone($0) } @@ -544,7 +551,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-209768682] = { return Api.messages.FavedStickers.parse_favedStickers($0) } dict[1776236393] = { return Api.ExportedChatInvite.parse_chatInviteEmpty($0) } dict[-64092740] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } - dict[-879268525] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } + dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[2079516406] = { return Api.Authorization.parse_authorization($0) } dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) } dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) } @@ -565,8 +572,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1289704741] = { return Api.SecureValueType.parse_secureValueTypePhone($0) } dict[-1908627474] = { return Api.SecureValueType.parse_secureValueTypeEmail($0) } dict[-732254058] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoUnknown($0) } - dict[-1237164374] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000($0) } - dict[1753693093] = { return Api.account.Password.parse_password($0) } + dict[982592842] = { return Api.PasswordKdfAlgo.parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow($0) } + dict[-1390001672] = { return Api.account.Password.parse_password($0) } dict[-1462213465] = { return Api.InputBotInlineResult.parse_inputBotInlineResultPhoto($0) } dict[-459324] = { return Api.InputBotInlineResult.parse_inputBotInlineResultDocument($0) } dict[1336154098] = { return Api.InputBotInlineResult.parse_inputBotInlineResultGame($0) } @@ -740,6 +747,8 @@ struct Api { _1.serialize(buffer, boxed) case let _1 as Api.account.TmpPassword: _1.serialize(buffer, boxed) + case let _1 as Api.SecureRequiredType: + _1.serialize(buffer, boxed) case let _1 as Api.Photo: _1.serialize(buffer, boxed) case let _1 as Api.Chat: @@ -770,6 +779,8 @@ struct Api { _1.serialize(buffer, boxed) case let _1 as Api.channels.ChannelParticipant: _1.serialize(buffer, boxed) + case let _1 as Api.InputCheckPasswordSRP: + _1.serialize(buffer, boxed) case let _1 as Api.storage.FileType: _1.serialize(buffer, boxed) case let _1 as Api.messages.ArchivedStickers: diff --git a/TelegramCore/Api1.swift b/TelegramCore/Api1.swift index 8eec9bd893..36fa5d0d45 100644 --- a/TelegramCore/Api1.swift +++ b/TelegramCore/Api1.swift @@ -970,6 +970,72 @@ extension Api { } } + } + enum SecureRequiredType: TypeConstructorDescription { + case secureRequiredType(flags: Int32, type: Api.SecureValueType) + case secureRequiredTypeOneOf(types: [Api.SecureRequiredType]) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureRequiredType(let flags, let type): + if boxed { + buffer.appendInt32(-2103600678) + } + serializeInt32(flags, buffer: buffer, boxed: false) + type.serialize(buffer, true) + break + case .secureRequiredTypeOneOf(let types): + if boxed { + buffer.appendInt32(41187252) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) + } + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .secureRequiredType(let flags, let type): + return ("secureRequiredType", [("flags", flags), ("type", type)]) + case .secureRequiredTypeOneOf(let types): + return ("secureRequiredTypeOneOf", [("types", types)]) + } + } + + static func parse_secureRequiredType(_ reader: BufferReader) -> SecureRequiredType? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureValueType? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.SecureRequiredType.secureRequiredType(flags: _1!, type: _2!) + } + else { + return nil + } + } + static func parse_secureRequiredTypeOneOf(_ reader: BufferReader) -> SecureRequiredType? { + var _1: [Api.SecureRequiredType]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureRequiredType.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.SecureRequiredType.secureRequiredTypeOneOf(types: _1!) + } + else { + return nil + } + } + } enum Photo: TypeConstructorDescription { case photoEmpty(id: Int64) @@ -2058,6 +2124,60 @@ extension Api { } } + } + enum InputCheckPasswordSRP: TypeConstructorDescription { + case inputCheckPasswordEmpty + case inputCheckPasswordSRP(srpId: Int64, A: Buffer, M1: Buffer) + + func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputCheckPasswordEmpty: + if boxed { + buffer.appendInt32(-1736378792) + } + + break + case .inputCheckPasswordSRP(let srpId, let A, let M1): + if boxed { + buffer.appendInt32(-763367294) + } + serializeInt64(srpId, buffer: buffer, boxed: false) + serializeBytes(A, buffer: buffer, boxed: false) + serializeBytes(M1, buffer: buffer, boxed: false) + break + } + } + + func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputCheckPasswordEmpty: + return ("inputCheckPasswordEmpty", []) + case .inputCheckPasswordSRP(let srpId, let A, let M1): + return ("inputCheckPasswordSRP", [("srpId", srpId), ("A", A), ("M1", M1)]) + } + } + + static func parse_inputCheckPasswordEmpty(_ reader: BufferReader) -> InputCheckPasswordSRP? { + return Api.InputCheckPasswordSRP.inputCheckPasswordEmpty + } + static func parse_inputCheckPasswordSRP(_ reader: BufferReader) -> InputCheckPasswordSRP? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputCheckPasswordSRP.inputCheckPasswordSRP(srpId: _1!, A: _2!, M1: _3!) + } + else { + return nil + } + } + } enum InputEncryptedFile: TypeConstructorDescription { case inputEncryptedFileEmpty @@ -8042,13 +8162,13 @@ extension Api { } enum InputSecureValue: TypeConstructorDescription { - case inputSecureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.InputSecureFile?, reverseSide: Api.InputSecureFile?, selfie: Api.InputSecureFile?, files: [Api.InputSecureFile]?, plainData: Api.SecurePlainData?) + case inputSecureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.InputSecureFile?, reverseSide: Api.InputSecureFile?, selfie: Api.InputSecureFile?, translation: [Api.InputSecureFile]?, files: [Api.InputSecureFile]?, plainData: Api.SecurePlainData?) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let files, let plainData): + case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData): if boxed { - buffer.appendInt32(108557032) + buffer.appendInt32(-618540889) } serializeInt32(flags, buffer: buffer, boxed: false) type.serialize(buffer, true) @@ -8056,6 +8176,11 @@ extension Api { if Int(flags) & Int(1 << 1) != 0 {frontSide!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {reverseSide!.serialize(buffer, true)} if Int(flags) & Int(1 << 3) != 0 {selfie!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(translation!.count)) + for item in translation! { + item.serialize(buffer, true) + }} if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) buffer.appendInt32(Int32(files!.count)) for item in files! { @@ -8068,8 +8193,8 @@ extension Api { func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let files, let plainData): - return ("inputSecureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("files", files), ("plainData", plainData)]) + case .inputSecureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData): + return ("inputSecureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("translation", translation), ("files", files), ("plainData", plainData)]) } } @@ -8097,12 +8222,16 @@ extension Api { _6 = Api.parse(reader, signature: signature) as? Api.InputSecureFile } } var _7: [Api.InputSecureFile]? - if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) } } - var _8: Api.SecurePlainData? + var _8: [Api.InputSecureFile]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) + } } + var _9: Api.SecurePlainData? if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.SecurePlainData + _9 = Api.parse(reader, signature: signature) as? Api.SecurePlainData } } let _c1 = _1 != nil let _c2 = _2 != nil @@ -8110,10 +8239,11 @@ extension Api { let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil - let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.InputSecureValue.inputSecureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, files: _7, plainData: _8) + let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.InputSecureValue.inputSecureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, translation: _7, files: _8, plainData: _9) } else { return nil @@ -8412,6 +8542,9 @@ extension Api { case secureValueErrorSelfie(type: Api.SecureValueType, fileHash: Buffer, text: String) case secureValueErrorFile(type: Api.SecureValueType, fileHash: Buffer, text: String) case secureValueErrorFiles(type: Api.SecureValueType, fileHash: [Buffer], text: String) + case secureValueError(type: Api.SecureValueType, hash: Buffer, text: String) + case secureValueErrorTranslationFile(type: Api.SecureValueType, fileHash: Buffer, text: String) + case secureValueErrorTranslationFiles(type: Api.SecureValueType, fileHash: [Buffer], text: String) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -8468,6 +8601,34 @@ extension Api { } serializeString(text, buffer: buffer, boxed: false) break + case .secureValueError(let type, let hash, let text): + if boxed { + buffer.appendInt32(-2036501105) + } + type.serialize(buffer, true) + serializeBytes(hash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorTranslationFile(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(-1592506512) + } + type.serialize(buffer, true) + serializeBytes(fileHash, buffer: buffer, boxed: false) + serializeString(text, buffer: buffer, boxed: false) + break + case .secureValueErrorTranslationFiles(let type, let fileHash, let text): + if boxed { + buffer.appendInt32(878931416) + } + type.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(fileHash.count)) + for item in fileHash { + serializeBytes(item, buffer: buffer, boxed: false) + } + serializeString(text, buffer: buffer, boxed: false) + break } } @@ -8485,6 +8646,12 @@ extension Api { return ("secureValueErrorFile", [("type", type), ("fileHash", fileHash), ("text", text)]) case .secureValueErrorFiles(let type, let fileHash, let text): return ("secureValueErrorFiles", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueError(let type, let hash, let text): + return ("secureValueError", [("type", type), ("hash", hash), ("text", text)]) + case .secureValueErrorTranslationFile(let type, let fileHash, let text): + return ("secureValueErrorTranslationFile", [("type", type), ("fileHash", fileHash), ("text", text)]) + case .secureValueErrorTranslationFiles(let type, let fileHash, let text): + return ("secureValueErrorTranslationFiles", [("type", type), ("fileHash", fileHash), ("text", text)]) } } @@ -8607,6 +8774,65 @@ extension Api { return nil } } + static func parse_secureValueError(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueError(type: _1!, hash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorTranslationFile(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorTranslationFile(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } + static func parse_secureValueErrorTranslationFiles(_ reader: BufferReader) -> SecureValueError? { + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: [Buffer]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self) + } + var _3: String? + _3 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.SecureValueError.secureValueErrorTranslationFiles(type: _1!, fileHash: _2!, text: _3!) + } + else { + return nil + } + } } enum ChannelBannedRights: TypeConstructorDescription { @@ -8950,13 +9176,13 @@ extension Api { } enum SecureValue: TypeConstructorDescription { - case secureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.SecureFile?, reverseSide: Api.SecureFile?, selfie: Api.SecureFile?, files: [Api.SecureFile]?, plainData: Api.SecurePlainData?, hash: Buffer) + case secureValue(flags: Int32, type: Api.SecureValueType, data: Api.SecureData?, frontSide: Api.SecureFile?, reverseSide: Api.SecureFile?, selfie: Api.SecureFile?, translation: [Api.SecureFile]?, files: [Api.SecureFile]?, plainData: Api.SecurePlainData?, hash: Buffer) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let files, let plainData, let hash): + case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData, let hash): if boxed { - buffer.appendInt32(-1263225191) + buffer.appendInt32(411017418) } serializeInt32(flags, buffer: buffer, boxed: false) type.serialize(buffer, true) @@ -8964,6 +9190,11 @@ extension Api { if Int(flags) & Int(1 << 1) != 0 {frontSide!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {reverseSide!.serialize(buffer, true)} if Int(flags) & Int(1 << 3) != 0 {selfie!.serialize(buffer, true)} + if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(translation!.count)) + for item in translation! { + item.serialize(buffer, true) + }} if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) buffer.appendInt32(Int32(files!.count)) for item in files! { @@ -8977,8 +9208,8 @@ extension Api { func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let files, let plainData, let hash): - return ("secureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("files", files), ("plainData", plainData), ("hash", hash)]) + case .secureValue(let flags, let type, let data, let frontSide, let reverseSide, let selfie, let translation, let files, let plainData, let hash): + return ("secureValue", [("flags", flags), ("type", type), ("data", data), ("frontSide", frontSide), ("reverseSide", reverseSide), ("selfie", selfie), ("translation", translation), ("files", files), ("plainData", plainData), ("hash", hash)]) } } @@ -9006,26 +9237,31 @@ extension Api { _6 = Api.parse(reader, signature: signature) as? Api.SecureFile } } var _7: [Api.SecureFile]? - if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() { _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) } } - var _8: Api.SecurePlainData? - if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.SecurePlainData + var _8: [Api.SecureFile]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) } } - var _9: Buffer? - _9 = parseBytes(reader) + var _9: Api.SecurePlainData? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.SecurePlainData + } } + var _10: Buffer? + _10 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil - let _c8 = (Int(_1!) & Int(1 << 5) == 0) || _8 != nil - let _c9 = _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.SecureValue.secureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, files: _7, plainData: _8, hash: _9!) + let _c7 = (Int(_1!) & Int(1 << 6) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.SecureValue.secureValue(flags: _1!, type: _2!, data: _3, frontSide: _4, reverseSide: _5, selfie: _6, translation: _7, files: _8, plainData: _9, hash: _10!) } else { return nil @@ -13923,7 +14159,7 @@ extension Api { } enum PasswordKdfAlgo: TypeConstructorDescription { case passwordKdfAlgoUnknown - case passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(salt1: Buffer, salt2: Buffer) + case passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: Buffer, salt2: Buffer, g: Int32, p: Buffer) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -13933,12 +14169,14 @@ extension Api { } break - case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(let salt1, let salt2): + case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(let salt1, let salt2, let g, let p): if boxed { - buffer.appendInt32(-1237164374) + buffer.appendInt32(982592842) } serializeBytes(salt1, buffer: buffer, boxed: false) serializeBytes(salt2, buffer: buffer, boxed: false) + serializeInt32(g, buffer: buffer, boxed: false) + serializeBytes(p, buffer: buffer, boxed: false) break } } @@ -13947,23 +14185,29 @@ extension Api { switch self { case .passwordKdfAlgoUnknown: return ("passwordKdfAlgoUnknown", []) - case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(let salt1, let salt2): - return ("passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000", [("salt1", salt1), ("salt2", salt2)]) + case .passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(let salt1, let salt2, let g, let p): + return ("passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow", [("salt1", salt1), ("salt2", salt2), ("g", g), ("p", p)]) } } static func parse_passwordKdfAlgoUnknown(_ reader: BufferReader) -> PasswordKdfAlgo? { return Api.PasswordKdfAlgo.passwordKdfAlgoUnknown } - static func parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(_ reader: BufferReader) -> PasswordKdfAlgo? { + static func parse_passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(_ reader: BufferReader) -> PasswordKdfAlgo? { var _1: Buffer? _1 = parseBytes(reader) var _2: Buffer? _2 = parseBytes(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil - if _c1 && _c2 { - return Api.PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000(salt1: _1!, salt2: _2!) + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow(salt1: _1!, salt2: _2!, g: _3!, p: _4!) } else { return nil diff --git a/TelegramCore/Api3.swift b/TelegramCore/Api3.swift index b07e919b0d..59cbbfb91d 100644 --- a/TelegramCore/Api3.swift +++ b/TelegramCore/Api3.swift @@ -603,13 +603,13 @@ struct account { } enum AuthorizationForm: TypeConstructorDescription { - case authorizationForm(flags: Int32, requiredTypes: [Api.SecureValueType], values: [Api.SecureValue], errors: [Api.SecureValueError], users: [Api.User], privacyPolicyUrl: String?) + case authorizationForm(flags: Int32, requiredTypes: [Api.SecureRequiredType], values: [Api.SecureValue], errors: [Api.SecureValueError], users: [Api.User], privacyPolicyUrl: String?) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { case .authorizationForm(let flags, let requiredTypes, let values, let errors, let users, let privacyPolicyUrl): if boxed { - buffer.appendInt32(-879268525) + buffer.appendInt32(-1389486888) } serializeInt32(flags, buffer: buffer, boxed: false) buffer.appendInt32(481674261) @@ -647,9 +647,9 @@ struct account { static func parse_authorizationForm(_ reader: BufferReader) -> AuthorizationForm? { var _1: Int32? _1 = reader.readInt32() - var _2: [Api.SecureValueType]? + var _2: [Api.SecureRequiredType]? if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValueType.self) + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureRequiredType.self) } var _3: [Api.SecureValue]? if let _ = reader.readInt32() { @@ -681,16 +681,18 @@ struct account { } enum Password: TypeConstructorDescription { - case password(flags: Int32, currentAlgo: Api.PasswordKdfAlgo?, hint: String?, emailUnconfirmedPattern: String?, newAlgo: Api.PasswordKdfAlgo, newSecureAlgo: Api.SecurePasswordKdfAlgo, secureRandom: Buffer) + case password(flags: Int32, currentAlgo: Api.PasswordKdfAlgo?, srpB: Buffer?, srpId: Int64?, hint: String?, emailUnconfirmedPattern: String?, newAlgo: Api.PasswordKdfAlgo, newSecureAlgo: Api.SecurePasswordKdfAlgo, secureRandom: Buffer) func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .password(let flags, let currentAlgo, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): + case .password(let flags, let currentAlgo, let srpB, let srpId, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): if boxed { - buffer.appendInt32(1753693093) + buffer.appendInt32(-1390001672) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 2) != 0 {currentAlgo!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(srpB!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt64(srpId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 3) != 0 {serializeString(hint!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 4) != 0 {serializeString(emailUnconfirmedPattern!, buffer: buffer, boxed: false)} newAlgo.serialize(buffer, true) @@ -702,8 +704,8 @@ struct account { func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .password(let flags, let currentAlgo, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): - return ("password", [("flags", flags), ("currentAlgo", currentAlgo), ("hint", hint), ("emailUnconfirmedPattern", emailUnconfirmedPattern), ("newAlgo", newAlgo), ("newSecureAlgo", newSecureAlgo), ("secureRandom", secureRandom)]) + case .password(let flags, let currentAlgo, let srpB, let srpId, let hint, let emailUnconfirmedPattern, let newAlgo, let newSecureAlgo, let secureRandom): + return ("password", [("flags", flags), ("currentAlgo", currentAlgo), ("srpB", srpB), ("srpId", srpId), ("hint", hint), ("emailUnconfirmedPattern", emailUnconfirmedPattern), ("newAlgo", newAlgo), ("newSecureAlgo", newSecureAlgo), ("secureRandom", secureRandom)]) } } @@ -714,29 +716,35 @@ struct account { if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() { _2 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo } } - var _3: String? - if Int(_1!) & Int(1 << 3) != 0 {_3 = parseString(reader) } - var _4: String? - if Int(_1!) & Int(1 << 4) != 0 {_4 = parseString(reader) } - var _5: Api.PasswordKdfAlgo? + var _3: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_3 = parseBytes(reader) } + var _4: Int64? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt64() } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 4) != 0 {_6 = parseString(reader) } + var _7: Api.PasswordKdfAlgo? if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo + _7 = Api.parse(reader, signature: signature) as? Api.PasswordKdfAlgo } - var _6: Api.SecurePasswordKdfAlgo? + var _8: Api.SecurePasswordKdfAlgo? if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.SecurePasswordKdfAlgo + _8 = Api.parse(reader, signature: signature) as? Api.SecurePasswordKdfAlgo } - var _7: Buffer? - _7 = parseBytes(reader) + var _9: Buffer? + _9 = parseBytes(reader) let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 2) == 0) || _2 != nil - let _c3 = (Int(_1!) & Int(1 << 3) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil + let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil let _c7 = _7 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { - return Api.account.Password.password(flags: _1!, currentAlgo: _2, hint: _3, emailUnconfirmedPattern: _4, newAlgo: _5!, newSecureAlgo: _6!, secureRandom: _7!) + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.account.Password.password(flags: _1!, currentAlgo: _2, srpB: _3, srpId: _4, hint: _5, emailUnconfirmedPattern: _6, newAlgo: _7!, newSecureAlgo: _8!, secureRandom: _9!) } else { return nil @@ -3459,20 +3467,6 @@ extension Api { }) } - static func checkPassword(passwordHash: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(174260510) - serializeBytes(passwordHash, buffer: buffer, boxed: false) - return (FunctionDescription(name: "auth.checkPassword", parameters: [("passwordHash", passwordHash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in - let reader = BufferReader(buffer) - var result: Api.auth.Authorization? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.auth.Authorization - } - return result - }) - } - static func requestPasswordRecovery() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(-661144474) @@ -3548,6 +3542,20 @@ extension Api { return result }) } + + static func checkPassword(password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-779399914) + password.serialize(buffer, true) + return (FunctionDescription(name: "auth.checkPassword", parameters: [("password", password)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.Authorization? in + let reader = BufferReader(buffer) + var result: Api.auth.Authorization? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + return result + }) + } } struct bots { static func sendCustomRequest(customMethod: String, params: Api.DataJSON) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -4564,35 +4572,6 @@ extension Api { }) } - static func getPasswordSettings(currentPasswordHash: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-1131605573) - serializeBytes(currentPasswordHash, buffer: buffer, boxed: false) - return (FunctionDescription(name: "account.getPasswordSettings", parameters: [("currentPasswordHash", currentPasswordHash)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.PasswordSettings? in - let reader = BufferReader(buffer) - var result: Api.account.PasswordSettings? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.account.PasswordSettings - } - return result - }) - } - - static func updatePasswordSettings(currentPasswordHash: Buffer, newSettings: Api.account.PasswordInputSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-92517498) - serializeBytes(currentPasswordHash, buffer: buffer, boxed: false) - newSettings.serialize(buffer, true) - return (FunctionDescription(name: "account.updatePasswordSettings", parameters: [("currentPasswordHash", currentPasswordHash), ("newSettings", newSettings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in - let reader = BufferReader(buffer) - var result: Api.Bool? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Bool - } - return result - }) - } - static func sendConfirmPhoneCode(flags: Int32, hash: String, currentNumber: Api.Bool?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(353818557) @@ -4624,21 +4603,6 @@ extension Api { }) } - static func getTmpPassword(passwordHash: Buffer, period: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1250046590) - serializeBytes(passwordHash, buffer: buffer, boxed: false) - serializeInt32(period, buffer: buffer, boxed: false) - return (FunctionDescription(name: "account.getTmpPassword", parameters: [("passwordHash", passwordHash), ("period", period)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.TmpPassword? in - let reader = BufferReader(buffer) - var result: Api.account.TmpPassword? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.account.TmpPassword - } - return result - }) - } - static func unregisterDevice(tokenType: Int32, token: String, otherUids: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(813089983) @@ -4886,6 +4850,50 @@ extension Api { return result }) } + + static func getTmpPassword(password: Api.InputCheckPasswordSRP, period: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1151208273) + password.serialize(buffer, true) + serializeInt32(period, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getTmpPassword", parameters: [("password", password), ("period", period)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.TmpPassword? in + let reader = BufferReader(buffer) + var result: Api.account.TmpPassword? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.TmpPassword + } + return result + }) + } + + static func updatePasswordSettings(password: Api.InputCheckPasswordSRP, newSettings: Api.account.PasswordInputSettings) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1516564433) + password.serialize(buffer, true) + newSettings.serialize(buffer, true) + return (FunctionDescription(name: "account.updatePasswordSettings", parameters: [("password", password), ("newSettings", newSettings)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + static func getPasswordSettings(password: Api.InputCheckPasswordSRP) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1663767815) + password.serialize(buffer, true) + return (FunctionDescription(name: "account.getPasswordSettings", parameters: [("password", password)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.PasswordSettings? in + let reader = BufferReader(buffer) + var result: Api.account.PasswordSettings? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.PasswordSettings + } + return result + }) + } } struct langpack { static func getLangPack(langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/TelegramCore/BlockedPeers.swift b/TelegramCore/BlockedPeers.swift index 22da57c34c..571992b3de 100644 --- a/TelegramCore/BlockedPeers.swift +++ b/TelegramCore/BlockedPeers.swift @@ -46,7 +46,7 @@ public func requestUpdatePeerIsBlocked(account: Account, peerId: PeerId, isBlock signal = account.network.request(Api.functions.contacts.unblock(id: inputUser)) } return signal - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/CallSessionManager.swift b/TelegramCore/CallSessionManager.swift index 3b7ea50f9f..4a29355463 100644 --- a/TelegramCore/CallSessionManager.swift +++ b/TelegramCore/CallSessionManager.swift @@ -783,7 +783,7 @@ private func acceptCallSession(postbox: Postbox, network: Network, stableId: Cal let gb = MTExp(g, bData, p)! return network.request(Api.functions.phone.acceptCall(peer: .inputPhoneCall(id: stableId, accessHash: accessHash), gB: Buffer(data: gb), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: kCallMinLayer, maxLayer: kCallMaxLayer))) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -879,7 +879,7 @@ private func requestCallSession(postbox: Postbox, network: Network, peerId: Peer private func confirmCallSession(network: Network, stableId: CallSessionStableId, accessHash: Int64, gA: Data, keyFingerprint: Int64) -> Signal { return network.request(Api.functions.phone.confirmCall(peer: Api.InputPhoneCall.inputPhoneCall(id: stableId, accessHash: accessHash), gA: Buffer(data: gA), keyFingerprint: keyFingerprint, protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: kCallMinLayer, maxLayer: kCallMaxLayer))) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -920,7 +920,7 @@ private func dropCallSession(network: Network, addUpdates: @escaping (Api.Update mappedReason = .phoneCallDiscardReasonMissed } return network.request(Api.functions.phone.discardCall(peer: Api.InputPhoneCall.inputPhoneCall(id: stableId, accessHash: accessHash), duration: duration, reason: mappedReason, connectionId: 0)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/ChannelAdminEventLogContext.swift b/TelegramCore/ChannelAdminEventLogContext.swift index b4dbaf8d75..08a91cf544 100644 --- a/TelegramCore/ChannelAdminEventLogContext.swift +++ b/TelegramCore/ChannelAdminEventLogContext.swift @@ -93,10 +93,11 @@ public final class ChannelAdminEventLogContext { private var stableIds: [AdminLogEventId: UInt32] = [:] private var entries: ([ChannelAdminEventLogEntry], ChannelAdminEventLogFilter) = ([], ChannelAdminEventLogFilter()) + private var hasEntries: Bool = false private var hasEarlier: Bool = true private var loadingMoreEarlier: Bool = false - private var subscribers = Bag<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType) -> Void>() + private var subscribers = Bag<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType, Bool) -> Void>() private let loadMoreDisposable = MetaDisposable() @@ -110,14 +111,14 @@ public final class ChannelAdminEventLogContext { self.loadMoreDisposable.dispose() } - public func get() -> Signal<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType), NoError> { + public func get() -> Signal<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType, Bool), NoError> { let queue = self.queue return Signal { [weak self] subscriber in if let strongSelf = self { - subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, .initial)) + subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, .initial, strongSelf.hasEntries)) - let index = strongSelf.subscribers.add({ entries, hasEarlier, type in - subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, type)) + let index = strongSelf.subscribers.add({ entries, hasEarlier, type, hasEntries in + subscriber.putNext((entries, hasEarlier, type, hasEntries)) }) return ActionDisposable { @@ -138,9 +139,10 @@ public final class ChannelAdminEventLogContext { self.filter = filter self.loadingMoreEarlier = false self.hasEarlier = false + self.hasEntries = false for subscriber in self.subscribers.copyItems() { - subscriber(self.entries.0, self.hasEarlier, .load) + subscriber(self.entries.0, self.hasEarlier, .load, self.hasEntries) } self.loadMoreEntries() @@ -193,9 +195,10 @@ public final class ChannelAdminEventLogContext { strongSelf.hasEarlier = !events.isEmpty strongSelf.loadingMoreEarlier = false + strongSelf.hasEntries = true for subscriber in strongSelf.subscribers.copyItems() { - subscriber(strongSelf.entries.0, strongSelf.hasEarlier, .load) + subscriber(strongSelf.entries.0, strongSelf.hasEarlier, .load, strongSelf.hasEntries) } } })) diff --git a/TelegramCore/ChannelAdminEventLogs.swift b/TelegramCore/ChannelAdminEventLogs.swift index b9aa3673e7..d6438cc707 100644 --- a/TelegramCore/ChannelAdminEventLogs.swift +++ b/TelegramCore/ChannelAdminEventLogs.swift @@ -102,7 +102,7 @@ public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: Pe return postbox.transaction { transaction -> (Peer?, [Peer]?) in return (transaction.getPeer(peerId), admins?.flatMap { transaction.getPeer($0) }) } - |> mapError { return .generic } + |> introduceError(ChannelAdminLogEventError.self) |> mapToSignal { (peer, admins) -> Signal in if let peer = peer, let inputChannel = apiInputChannel(peer) { let inputAdmins = admins?.flatMap {apiInputUser($0)} diff --git a/TelegramCore/ChannelAdmins.swift b/TelegramCore/ChannelAdmins.swift index 020ff331b9..99649f55e2 100644 --- a/TelegramCore/ChannelAdmins.swift +++ b/TelegramCore/ChannelAdmins.swift @@ -56,7 +56,7 @@ public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedC } |> switchToLatest } -public func channelAdminIds(postbox: Postbox, network: Network, peerId: PeerId, hash: Int32) -> Signal<[PeerId], Void> { +public func channelAdminIds(postbox: Postbox, network: Network, peerId: PeerId, hash: Int32) -> Signal<[PeerId], NoError> { return postbox.transaction { transaction in if let peer = transaction.getPeer(peerId) as? TelegramChannel, case .group = peer.info, let apiChannel = apiInputChannel(peer) { let api = Api.functions.channels.getParticipants(channel: apiChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: hash) @@ -74,8 +74,8 @@ public func channelAdminIds(postbox: Postbox, network: Network, peerId: PeerId, }) }) return .single(users.map({TelegramUser(user: $0).id})) - default: - return .complete() + default: + return .complete() } } } diff --git a/TelegramCore/ChannelCreation.swift b/TelegramCore/ChannelCreation.swift index bff9e57317..f815569f4e 100644 --- a/TelegramCore/ChannelCreation.swift +++ b/TelegramCore/ChannelCreation.swift @@ -12,7 +12,7 @@ import Foundation public func createChannel(account: Account, title: String, description: String?) -> Signal { return account.postbox.transaction { transaction -> Signal in return account.network.request(Api.functions.channels.createChannel(flags: 1 << 0, title: title, about: description ?? ""), automaticFloodWait: false) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ in return Signal.single(nil) } diff --git a/TelegramCore/ChannelHistoryAvailabilitySettings.swift b/TelegramCore/ChannelHistoryAvailabilitySettings.swift index c15e336a88..b972c3d9d7 100644 --- a/TelegramCore/ChannelHistoryAvailabilitySettings.swift +++ b/TelegramCore/ChannelHistoryAvailabilitySettings.swift @@ -6,30 +6,37 @@ import SwiftSignalKit #endif -public func updateChannelHistoryAvailabilitySettingsInteractively(postbox: Postbox, network: Network, peerId: PeerId, historyAvailableForNewMembers: Bool) -> Signal { +public func updateChannelHistoryAvailabilitySettingsInteractively(postbox: Postbox, network: Network, accountStateManager: AccountStateManager, peerId: PeerId, historyAvailableForNewMembers: Bool) -> Signal { return postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { return network.request(Api.functions.channels.togglePreHistoryHidden(channel: inputChannel, enabled: historyAvailableForNewMembers ? .boolFalse : .boolTrue)) - |> mapError {_ in} - |> mapToSignal { _ -> Signal in - return postbox.transaction { transaction -> Void in - transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in - if let currentData = currentData as? CachedChannelData { - var flags = currentData.flags - if historyAvailableForNewMembers { - flags.insert(.preHistoryEnabled) - } else { - flags.remove(.preHistoryEnabled) - } - return currentData.withUpdatedFlags(flags) - } else { - return currentData - } - }) - } + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + accountStateManager.addUpdates(updates) } + return postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in + if let currentData = currentData as? CachedChannelData { + var flags = currentData.flags + if historyAvailableForNewMembers { + flags.insert(.preHistoryEnabled) + } else { + flags.remove(.preHistoryEnabled) + } + return currentData.withUpdatedFlags(flags) + } else { + return currentData + } + }) + } + } } else { return .complete() } - } |> switchToLatest + } + |> switchToLatest } diff --git a/TelegramCore/ChatContextResult.swift b/TelegramCore/ChatContextResult.swift index 8de80853c2..45184b2d41 100644 --- a/TelegramCore/ChatContextResult.swift +++ b/TelegramCore/ChatContextResult.swift @@ -115,7 +115,7 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable { } case let .mapLocation(lhsMedia, lhsReplyMarkup): if case let .mapLocation(rhsMedia, rhsReplyMarkup) = rhs { - if !lhsMedia.isEqual(rhsMedia) { + if !lhsMedia.isEqual(to: rhsMedia) { return false } if lhsReplyMarkup != rhsReplyMarkup { @@ -127,7 +127,7 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable { } case let .contact(lhsMedia, lhsReplyMarkup): if case let .contact(rhsMedia, rhsReplyMarkup) = rhs { - if !lhsMedia.isEqual(rhsMedia) { + if !lhsMedia.isEqual(to: rhsMedia) { return false } if lhsReplyMarkup != rhsReplyMarkup { @@ -223,14 +223,14 @@ public enum ChatContextResult: Equatable { return false } if let lhsContent = lhsContent, let rhsContent = rhsContent { - if !lhsContent.isEqual(rhsContent) { + if !lhsContent.isEqual(to: rhsContent) { return false } } else if (lhsContent != nil) != (rhsContent != nil) { return false } if let lhsThumbnail = lhsThumbnail, let rhsThumbnail = rhsThumbnail { - if !lhsThumbnail.isEqual(rhsThumbnail) { + if !lhsThumbnail.isEqual(to: rhsThumbnail) { return false } } else if (lhsThumbnail != nil) != (rhsThumbnail != nil) { @@ -261,14 +261,14 @@ public enum ChatContextResult: Equatable { return false } if let lhsImage = lhsImage, let rhsImage = rhsImage { - if !lhsImage.isEqual(rhsImage) { + if !lhsImage.isEqual(to: rhsImage) { return false } } else if (lhsImage != nil) != (rhsImage != nil) { return false } if let lhsFile = lhsFile, let rhsFile = rhsFile { - if !lhsFile.isEqual(rhsFile) { + if !lhsFile.isEqual(to: rhsFile) { return false } } else if (lhsFile != nil) != (rhsFile != nil) { diff --git a/TelegramCore/ContactManagement.swift b/TelegramCore/ContactManagement.swift index 5a86d048c6..3847b9929e 100644 --- a/TelegramCore/ContactManagement.swift +++ b/TelegramCore/ContactManagement.swift @@ -87,7 +87,7 @@ public func addContactPeerInteractively(account: Account, peerId: PeerId, phone: return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId) as? TelegramUser, let phone = phone ?? peer.phone, !phone.isEmpty { return account.network.request(Api.functions.contacts.importContacts(contacts: [Api.InputContact.inputPhoneContact(clientId: 1, phone: phone, firstName: peer.firstName ?? "", lastName: peer.lastName ?? "")])) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -121,7 +121,7 @@ public func deleteContactPeerInteractively(account: Account, peerId: PeerId) -> return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { return account.network.request(Api.functions.contacts.deleteContact(id: inputUser)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/CreateGroup.swift b/TelegramCore/CreateGroup.swift index fb38e637b1..e656106d6a 100644 --- a/TelegramCore/CreateGroup.swift +++ b/TelegramCore/CreateGroup.swift @@ -20,7 +20,7 @@ public func createGroup(account: Account, title: String, peerIds: [PeerId]) -> S } } return account.network.request(Api.functions.messages.createChat(users: inputUsers, title: title)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ in return Signal.single(nil) } diff --git a/TelegramCore/DeepLinkInfo.swift b/TelegramCore/DeepLinkInfo.swift index ca71be6476..c473c19ffd 100644 --- a/TelegramCore/DeepLinkInfo.swift +++ b/TelegramCore/DeepLinkInfo.swift @@ -11,8 +11,9 @@ public struct DeepLinkInfo { public let updateApp: Bool } -public func getDeepLinkInfo(network: Network, path: String) -> Signal { - return network.request(Api.functions.help.getDeepLinkInfo(path: path)) |> retryRequest |> map { value -> DeepLinkInfo? in +public func getDeepLinkInfo(network: Network, path: String) -> Signal { + return network.request(Api.functions.help.getDeepLinkInfo(path: path)) |> retryRequest + |> map { value -> DeepLinkInfo? in switch value { case .deepLinkInfoEmpty: return nil diff --git a/TelegramCore/DeleteMessagesInteractively.swift b/TelegramCore/DeleteMessagesInteractively.swift index 75c47aecec..d66a3a346d 100644 --- a/TelegramCore/DeleteMessagesInteractively.swift +++ b/TelegramCore/DeleteMessagesInteractively.swift @@ -99,7 +99,7 @@ public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signa } public func clearAuthorHistory(account: Account, peerId: PeerId, memberId: PeerId) -> Signal { - return account.postbox.transaction { transaction -> Signal in + return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let memberPeer = transaction.getPeer(memberId), let inputChannel = apiInputChannel(peer), let inputUser = apiInputUser(memberPeer) { let signal = account.network.request(Api.functions.channels.deleteUserHistory(channel: inputChannel, userId: inputUser)) diff --git a/TelegramCore/Download.swift b/TelegramCore/Download.swift index e8683db66f..b6d11bce5e 100644 --- a/TelegramCore/Download.swift +++ b/TelegramCore/Download.swift @@ -181,7 +181,7 @@ class Download: NSObject, MTRequestMessageServiceDelegate { } |> retryRequest } - func part(location: Api.InputFileLocation, offset: Int, length: Int) -> Signal { + func part(location: Api.InputFileLocation, offset: Int, length: Int) -> Signal { return Signal { subscriber in let request = MTRequest() @@ -227,7 +227,8 @@ class Download: NSObject, MTRequestMessageServiceDelegate { return ActionDisposable { self.requestService.removeRequest(byInternalId: internalId) } - } |> retryRequest + } + |> retryRequest } func request(_ data: (FunctionDescription, Buffer, DeserializeFunctionResponse)) -> Signal { diff --git a/TelegramCore/EarliestUnseenPersonalMentionMessage.swift b/TelegramCore/EarliestUnseenPersonalMentionMessage.swift index ad2d2262d5..484838c7cf 100644 --- a/TelegramCore/EarliestUnseenPersonalMentionMessage.swift +++ b/TelegramCore/EarliestUnseenPersonalMentionMessage.swift @@ -65,6 +65,9 @@ private func earliestUnseenPersonalMentionMessage(postbox: Postbox, network: Net if !locally, let _ = invalidateHistoryPts { let validateSignal = fetchMessageHistoryHole(source: .network(network), postbox: postbox, hole: MessageHistoryHole(stableId: UInt32.max, maxIndex: MessageIndex.upperBound(peerId: peerId), min: resultMessage.id.id - 1, tags: 0), direction: .LowerToUpper, tagMask: .unseenPersonalMessage) + |> `catch` { _ -> Signal in + return .complete() + } |> mapToSignal { _ -> Signal in return .complete() } @@ -75,6 +78,9 @@ private func earliestUnseenPersonalMentionMessage(postbox: Postbox, network: Net } } else if let resultHole = resultHole, !locally { let validateSignal = fetchMessageHistoryHole(source: .network(network), postbox: postbox, hole: resultHole, direction: .LowerToUpper, tagMask: .unseenPersonalMessage) + |> `catch` { _ -> Signal in + return .complete() + } |> mapToSignal { _ -> Signal in return .complete() } diff --git a/TelegramCore/EnqueueMessage.swift b/TelegramCore/EnqueueMessage.swift index 05eabcaaff..b6585646dc 100644 --- a/TelegramCore/EnqueueMessage.swift +++ b/TelegramCore/EnqueueMessage.swift @@ -278,7 +278,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, } if let file = mediaReference?.media as? TelegramMediaFile, file.isVoice { - if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.SecretChat { attributes.append(ConsumableContentMessageAttribute(consumed: false)) } } diff --git a/TelegramCore/ExportMessageLink.swift b/TelegramCore/ExportMessageLink.swift index 755725d4f3..de6603aa31 100644 --- a/TelegramCore/ExportMessageLink.swift +++ b/TelegramCore/ExportMessageLink.swift @@ -8,22 +8,23 @@ #endif -public func exportMessageLink(account:Account, peerId:PeerId, messageId:MessageId) -> Signal { +public func exportMessageLink(account:Account, peerId:PeerId, messageId:MessageId) -> Signal { return account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) - } |> mapToSignal { peer -> Signal in - if let peer = peer, let input = apiInputChannel(peer) { - return account.network.request(Api.functions.channels.exportMessageLink(channel: input, id: messageId.id, grouped: .boolTrue)) |> mapError {_ in return } |> map { res in + } + |> mapToSignal { peer -> Signal in + if let peer = peer, let input = apiInputChannel(peer) { + return account.network.request(Api.functions.channels.exportMessageLink(channel: input, id: messageId.id, grouped: .boolTrue)) |> mapError {_ in return } |> map { res in - switch res { - case let .exportedMessageLink(link, _): - return link - } - } |> `catch` { _ -> Signal in - return .single(nil) + switch res { + case let .exportedMessageLink(link, _): + return link } - } else { - return .single(nil) + } |> `catch` { _ -> Signal in + return .single(nil) } + } else { + return .single(nil) + } } } diff --git a/TelegramCore/FetchChatList.swift b/TelegramCore/FetchChatList.swift index 5b5242f7a1..2ad894be7c 100644 --- a/TelegramCore/FetchChatList.swift +++ b/TelegramCore/FetchChatList.swift @@ -206,7 +206,7 @@ func fetchChatList(postbox: Postbox, network: Network, location: FetchChatListLo if case .general = location, case .inputPeerEmpty = peer, timestamp == 0 { additionalPinnedChats = network.request(Api.functions.messages.getPinnedDialogs()) |> retryRequest - |> map { Optional($0) } + |> map(Optional.init) } else { additionalPinnedChats = .single(nil) } diff --git a/TelegramCore/FetchedMediaResource.swift b/TelegramCore/FetchedMediaResource.swift index ab61a0dad5..3509b5be3e 100644 --- a/TelegramCore/FetchedMediaResource.swift +++ b/TelegramCore/FetchedMediaResource.swift @@ -115,31 +115,31 @@ public enum AnyMediaReference: Equatable { public static func ==(lhs: AnyMediaReference, rhs: AnyMediaReference) -> Bool { switch lhs { case let .standalone(lhsMedia): - if case let .standalone(rhsMedia) = rhs, lhsMedia.isEqual(rhsMedia) { + if case let .standalone(rhsMedia) = rhs, lhsMedia.isEqual(to: rhsMedia) { return true } else { return false } case let .message(lhsMessage, lhsMedia): - if case let .message(rhsMessage, rhsMedia) = rhs, lhsMessage == rhsMessage, lhsMedia.isEqual(rhsMedia) { + if case let .message(rhsMessage, rhsMedia) = rhs, lhsMessage == rhsMessage, lhsMedia.isEqual(to: rhsMedia) { return true } else { return false } case let .webPage(lhsWebPage, lhsMedia): - if case let .webPage(rhsWebPage, rhsMedia) = rhs, lhsWebPage == rhsWebPage, lhsMedia.isEqual(rhsMedia) { + if case let .webPage(rhsWebPage, rhsMedia) = rhs, lhsWebPage == rhsWebPage, lhsMedia.isEqual(to: rhsMedia) { return true } else { return false } case let .stickerPack(lhsStickerPack, lhsMedia): - if case let .stickerPack(rhsStickerPack, rhsMedia) = rhs, lhsStickerPack == rhsStickerPack, lhsMedia.isEqual(rhsMedia) { + if case let .stickerPack(rhsStickerPack, rhsMedia) = rhs, lhsStickerPack == rhsStickerPack, lhsMedia.isEqual(to: rhsMedia) { return true } else { return false } case let .savedGif(lhsMedia): - if case let .savedGif(rhsMedia) = rhs, lhsMedia.isEqual(rhsMedia) { + if case let .savedGif(rhsMedia) = rhs, lhsMedia.isEqual(to: rhsMedia) { return true } else { return false @@ -686,7 +686,7 @@ final class MediaReferenceRevalidationContext { func savedGifs(postbox: Postbox, network: Network) -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> { return self.genericItem(key: .savedGifs, request: { next, error in - let loadRecentGifs: Signal<[TelegramMediaFile], Void> = postbox.transaction { transaction -> [TelegramMediaFile] in + let loadRecentGifs: Signal<[TelegramMediaFile], NoError> = postbox.transaction { transaction -> [TelegramMediaFile] in return transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs).compactMap({ item -> TelegramMediaFile? in if let contents = item.contents as? RecentMediaItem, let file = contents.media as? TelegramMediaFile { return file @@ -695,13 +695,11 @@ final class MediaReferenceRevalidationContext { }) } return (managedRecentGifs(postbox: postbox, network: network, forceFetch: true) - |> mapToSignal { _ -> Signal<[TelegramMediaFile], Void> in + |> mapToSignal { _ -> Signal<[TelegramMediaFile], NoError> in return .complete() } |> then(loadRecentGifs) - |> mapError { _ -> RevalidateMediaReferenceError in - return .generic - }).start(next: { value in + |> introduceError(RevalidateMediaReferenceError.self)).start(next: { value in next(value) }, error: { _ in error(.generic) diff --git a/TelegramCore/GrantSecureIdAccess.swift b/TelegramCore/GrantSecureIdAccess.swift index b7a3d0eef8..0980d3559a 100644 --- a/TelegramCore/GrantSecureIdAccess.swift +++ b/TelegramCore/GrantSecureIdAccess.swift @@ -75,6 +75,39 @@ func apiSecureValueType(key: SecureIdValueKey) -> Api.SecureValueType { return type } +extension SecureIdValueKey { + init(apiType: Api.SecureValueType) { + switch apiType { + case .secureValueTypePersonalDetails: + self = .personalDetails + case .secureValueTypePassport: + self = .passport + case .secureValueTypeDriverLicense: + self = .driversLicense + case .secureValueTypeIdentityCard: + self = .idCard + case .secureValueTypeInternalPassport: + self = .internalPassport + case .secureValueTypeAddress: + self = .address + case .secureValueTypeUtilityBill: + self = .utilityBill + case .secureValueTypeBankStatement: + self = .bankStatement + case .secureValueTypeRentalAgreement: + self = .rentalAgreement + case .secureValueTypePassportRegistration: + self = .passportRegistration + case .secureValueTypeTemporaryRegistration: + self = .temporaryRegistration + case .secureValueTypePhone: + self = .phone + case .secureValueTypeEmail: + self = .email + } + } +} + private func credentialsValueTypeName(value: SecureIdValue) -> String { switch value { case .personalDetails: @@ -125,6 +158,15 @@ private func generateCredentials(values: [SecureIdValueWithContext], opaquePaylo ] } } + + if !value.translations.isEmpty { + valueDict["translation"] = value.translations.map { file -> [String: Any] in + return [ + "file_hash": file.hash.base64EncodedString(), + "secret": file.secret.base64EncodedString() + ] + } + } if let selfie = value.selfie { valueDict["selfie"] = [ diff --git a/TelegramCore/GroupsInCommon.swift b/TelegramCore/GroupsInCommon.swift index 6080da06d0..3e18dfedb1 100644 --- a/TelegramCore/GroupsInCommon.swift +++ b/TelegramCore/GroupsInCommon.swift @@ -7,16 +7,18 @@ import Foundation import SwiftSignalKit #endif -public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[PeerId], Void> { - return account.postbox.transaction { transaction -> Signal<[PeerId], Void> in +public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[PeerId], NoError> { + return account.postbox.transaction { transaction -> Signal<[PeerId], NoError> in if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { - return account.network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: 0, limit: 100)) |> mapError {_ in} |> mapToSignal { result -> Signal<[PeerId], Void> in - let chats:[Api.Chat] + return account.network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: 0, limit: 100)) + |> retryRequest + |> mapToSignal { result -> Signal<[PeerId], NoError> in + let chats: [Api.Chat] switch result { - case let .chats(chats: apiChats): - chats = apiChats - case let .chatsSlice(count: _, chats: apiChats): - chats = apiChats + case let .chats(chats: apiChats): + chats = apiChats + case let .chatsSlice(count: _, chats: apiChats): + chats = apiChats } return account.postbox.transaction { transaction -> [PeerId] in diff --git a/TelegramCore/Holes.swift b/TelegramCore/Holes.swift index 051a9f827a..fb0b9d7e69 100644 --- a/TelegramCore/Holes.swift +++ b/TelegramCore/Holes.swift @@ -42,89 +42,15 @@ enum FetchMessageHistoryHoleSource { func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Postbox, hole: MessageHistoryHole, direction: MessageHistoryViewRelativeHoleDirection, tagMask: MessageTags?, limit: Int = 100) -> Signal { assert(tagMask == nil || tagMask!.rawValue != 0) return postbox.loadedPeerWithId(hole.maxIndex.id.peerId) - |> take(1) - |> mapToSignal { peer in - if let inputPeer = apiInputPeer(peer) { - print("fetchMessageHistoryHole for \(peer.displayTitle) \(direction)") - let request: Signal - var maxIndexRequest: Signal = .single(nil) - var implicitelyFillHole = false - if let tagMask = tagMask { - if tagMask == MessageTags.unseenPersonalMessage { - let offsetId: Int32 - let addOffset: Int32 - let selectedLimit = limit - let maxId: Int32 - let minId: Int32 - - switch direction { - case .UpperToLower: - offsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - addOffset = 0 - maxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - minId = 1 - case .LowerToUpper: - offsetId = hole.min <= 1 ? 1 : (hole.min - 1) - addOffset = Int32(-selectedLimit) - maxId = Int32.max - minId = hole.min - 1 - case let .AroundId(id): - offsetId = id.id - addOffset = Int32(-selectedLimit / 2) - maxId = Int32.max - minId = 1 - case let .AroundIndex(index): - offsetId = index.id.id - addOffset = Int32(-selectedLimit / 2) - maxId = Int32.max - minId = 1 - } - request = source.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId)) - } else if tagMask == .liveLocation { - let selectedLimit = limit - - switch direction { - case .UpperToLower: - implicitelyFillHole = true - default: - assertionFailure() - } - request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0)) - } else if let filter = messageFilterForTagMask(tagMask) { - let offsetId: Int32 - let addOffset: Int32 - let selectedLimit = limit - let maxId: Int32 - let minId: Int32 - - switch direction { - case .UpperToLower: - offsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - addOffset = 0 - maxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - minId = 1 - case .LowerToUpper: - offsetId = hole.min <= 1 ? 1 : (hole.min - 1) - addOffset = Int32(-selectedLimit) - maxId = Int32.max - minId = hole.min - 1 - case let .AroundId(id): - offsetId = id.id - addOffset = Int32(-selectedLimit / 2) - maxId = Int32.max - minId = 1 - case let .AroundIndex(index): - offsetId = index.id.id - addOffset = Int32(-selectedLimit / 2) - maxId = Int32.max - minId = 1 - } - request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: hole.maxIndex.timestamp, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) - } else { - assertionFailure() - request = .never() - } - } else { + |> take(1) + |> mapToSignal { peer in + if let inputPeer = apiInputPeer(peer) { + print("fetchMessageHistoryHole for \(peer.displayTitle) \(direction)") + let request: Signal + var maxIndexRequest: Signal = .single(nil) + var implicitelyFillHole = false + if let tagMask = tagMask { + if tagMask == MessageTags.unseenPersonalMessage { let offsetId: Int32 let addOffset: Int32 let selectedLimit = limit @@ -142,12 +68,6 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos addOffset = Int32(-selectedLimit) maxId = Int32.max minId = hole.min - 1 - if hole.maxIndex.timestamp == Int32.max { - let innerOffsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - let innerMaxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) - maxIndexRequest = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: innerOffsetId, offsetDate: hole.maxIndex.timestamp, addOffset: 0, limit: 1, maxId: innerMaxId, minId: 1, hash: 0)) - |> map(Optional.init) - } case let .AroundId(id): offsetId = id.id addOffset = Int32(-selectedLimit / 2) @@ -159,113 +79,193 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos maxId = Int32.max minId = 1 } + request = source.request(Api.functions.messages.getUnreadMentions(peer: inputPeer, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId)) + } else if tagMask == .liveLocation { + let selectedLimit = limit - request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: hole.maxIndex.timestamp, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) + switch direction { + case .UpperToLower: + implicitelyFillHole = true + default: + assertionFailure() + } + request = source.request(Api.functions.messages.getRecentLocations(peer: inputPeer, limit: Int32(selectedLimit), hash: 0)) + } else if let filter = messageFilterForTagMask(tagMask) { + let offsetId: Int32 + let addOffset: Int32 + let selectedLimit = limit + let maxId: Int32 + let minId: Int32 + + switch direction { + case .UpperToLower: + offsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + addOffset = 0 + maxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + minId = 1 + case .LowerToUpper: + offsetId = hole.min <= 1 ? 1 : (hole.min - 1) + addOffset = Int32(-selectedLimit) + maxId = Int32.max + minId = hole.min - 1 + case let .AroundId(id): + offsetId = id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + case let .AroundIndex(index): + offsetId = index.id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + } + request = source.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: filter, minDate: 0, maxDate: hole.maxIndex.timestamp, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) + } else { + assertionFailure() + request = .never() + } + } else { + let offsetId: Int32 + let addOffset: Int32 + let selectedLimit = limit + let maxId: Int32 + let minId: Int32 + + switch direction { + case .UpperToLower: + offsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + addOffset = 0 + maxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + minId = 1 + case .LowerToUpper: + offsetId = hole.min <= 1 ? 1 : (hole.min - 1) + addOffset = Int32(-selectedLimit) + maxId = Int32.max + minId = hole.min - 1 + if hole.maxIndex.timestamp == Int32.max { + let innerOffsetId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + let innerMaxId = hole.maxIndex.id.id == Int32.max ? hole.maxIndex.id.id : (hole.maxIndex.id.id + 1) + maxIndexRequest = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: innerOffsetId, offsetDate: hole.maxIndex.timestamp, addOffset: 0, limit: 1, maxId: innerMaxId, minId: 1, hash: 0)) + |> map(Optional.init) + } + case let .AroundId(id): + offsetId = id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 + case let .AroundIndex(index): + offsetId = index.id.id + addOffset = Int32(-selectedLimit / 2) + maxId = Int32.max + minId = 1 } - return combineLatest(request |> retryRequest, maxIndexRequest |> retryRequest) - |> mapToSignal { result, maxIndexResult in - let messages: [Api.Message] - let chats: [Api.Chat] - let users: [Api.User] - var channelPts: Int32? - switch result { - case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - channelPts = pts + request = source.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: offsetId, offsetDate: hole.maxIndex.timestamp, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) + } + + return combineLatest(request |> retryRequest, maxIndexRequest |> retryRequest) + |> mapToSignal { result, maxIndexResult in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + var channelPts: Int32? + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + channelPts = pts + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + var updatedMaxIndex: MessageIndex? + if let maxIndexResult = maxIndexResult { + let maxIndexMessages: [Api.Message] + switch maxIndexResult { + case let .messages(apiMessages, _, _): + maxIndexMessages = apiMessages + case let .messagesSlice(_, apiMessages, _, _): + maxIndexMessages = apiMessages + case let .channelMessages(_, _, _, apiMessages, _, _): + maxIndexMessages = apiMessages case .messagesNotModified: - messages = [] - chats = [] - users = [] + maxIndexMessages = [] } - var updatedMaxIndex: MessageIndex? - if let maxIndexResult = maxIndexResult { - let maxIndexMessages: [Api.Message] - switch maxIndexResult { - case let .messages(apiMessages, _, _): - maxIndexMessages = apiMessages - case let .messagesSlice(_, apiMessages, _, _): - maxIndexMessages = apiMessages - case let .channelMessages(_, _, _, apiMessages, _, _): - maxIndexMessages = apiMessages - case .messagesNotModified: - maxIndexMessages = [] + if !maxIndexMessages.isEmpty { + assert(maxIndexMessages.count == 1) + if let storeMessage = StoreMessage(apiMessage: maxIndexMessages[0]), case let .Id(id) = storeMessage.id { + updatedMaxIndex = MessageIndex(id: id, timestamp: storeMessage.timestamp) } - if !maxIndexMessages.isEmpty { - assert(maxIndexMessages.count == 1) - if let storeMessage = StoreMessage(apiMessage: maxIndexMessages[0]), case let .Id(id) = storeMessage.id { - updatedMaxIndex = MessageIndex(id: id, timestamp: storeMessage.timestamp) - } - } - } - return postbox.transaction { transaction in - var storeMessages: [StoreMessage] = [] - - for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { - if let channelPts = channelPts { - var attributes = storeMessage.attributes - attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) - storeMessages.append(storeMessage.withUpdatedAttributes(attributes)) - } else { - storeMessages.append(storeMessage) - } - } - } - - let fillDirection: HoleFillDirection - switch direction { - case .UpperToLower: - fillDirection = .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil) - case .LowerToUpper: - fillDirection = .LowerToUpper(updatedMaxIndex: updatedMaxIndex, clippingMinIndex: nil) - case let .AroundId(id): - fillDirection = .AroundId(id, lowerComplete: false, upperComplete: false) - case let .AroundIndex(index): - fillDirection = .AroundId(index.id, lowerComplete: false, upperComplete: false) - } - - transaction.fillMultipleHoles(hole, fillType: HoleFill(complete: messages.count == 0 || implicitelyFillHole, direction: fillDirection), tagMask: tagMask, messages: storeMessages) - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in users { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - transaction.updatePeerPresences(peerPresences) - - print("fetchMessageHistoryHole for \(peer.displayTitle) done") - - return } } - } else { - return fail(Void.self, NoError()) - } + return postbox.transaction { transaction in + var storeMessages: [StoreMessage] = [] + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + if let channelPts = channelPts { + var attributes = storeMessage.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + storeMessages.append(storeMessage.withUpdatedAttributes(attributes)) + } else { + storeMessages.append(storeMessage) + } + } + } + + let fillDirection: HoleFillDirection + switch direction { + case .UpperToLower: + fillDirection = .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil) + case .LowerToUpper: + fillDirection = .LowerToUpper(updatedMaxIndex: updatedMaxIndex, clippingMinIndex: nil) + case let .AroundId(id): + fillDirection = .AroundId(id, lowerComplete: false, upperComplete: false) + case let .AroundIndex(index): + fillDirection = .AroundId(index.id, lowerComplete: false, upperComplete: false) + } + + transaction.fillMultipleHoles(hole, fillType: HoleFill(complete: messages.count == 0 || implicitelyFillHole, direction: fillDirection), tagMask: tagMask, messages: storeMessages) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + transaction.updatePeerPresences(peerPresences) + + print("fetchMessageHistoryHole for \(peer.displayTitle) done") + + return + } + } + } else { + return .complete() } + } } func groupBoundaryPeer(_ peerId: PeerId, accountPeerId: PeerId) -> Api.Peer { @@ -514,72 +514,72 @@ func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageInd let offset: Signal<(Int32, Int32, Api.InputPeer), NoError> offset = single((holeIndex.timestamp, min(holeIndex.id.id, Int32.max - 1) + 1, Api.InputPeer.inputPeerEmpty), NoError.self) return offset - |> mapToSignal { (timestamp, id, peer) -> Signal in - let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0)) - |> retryRequest - |> mapToSignal { result -> Signal in - let messages: [Api.Message] - let chats: [Api.Chat] - let users: [Api.User] - switch result { - case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case .messagesNotModified: - messages = [] - chats = [] - users = [] - } - return postbox.transaction { transaction -> Void in - var storeMessages: [StoreMessage] = [] - var topIndex: MessageIndex? - - for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { - storeMessages.append(storeMessage) - if let index = storeMessage.index, topIndex == nil || index < topIndex! { - topIndex = index - } - } + |> mapToSignal { (timestamp, id, peer) -> Signal in + let searchResult = network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", fromId: nil, filter: .inputMessagesFilterPhoneCalls(flags: 0), minDate: 0, maxDate: holeIndex.timestamp, offsetId: 0, addOffset: 0, limit: limit, maxId: holeIndex.id.id, minId: 0, hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal in + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] + } + return postbox.transaction { transaction -> Void in + var storeMessages: [StoreMessage] = [] + var topIndex: MessageIndex? + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + storeMessages.append(storeMessage) + if let index = storeMessage.index, topIndex == nil || index < topIndex! { + topIndex = index } - - var updatedIndex: MessageIndex? - if let topIndex = topIndex { - updatedIndex = topIndex.predecessor() - } - - transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages) - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in users { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - transaction.updatePeerPresences(peerPresences) } } - return searchResult + + var updatedIndex: MessageIndex? + if let topIndex = topIndex { + updatedIndex = topIndex.predecessor() + } + + transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages) + + var peers: [Peer] = [] + var peerPresences: [PeerId: PeerPresence] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + if let presence = TelegramUserPresence(apiUser: user) { + peerPresences[telegramUser.id] = presence + } + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + transaction.updatePeerPresences(peerPresences) + } } + return searchResult + } } diff --git a/TelegramCore/ImportContact.swift b/TelegramCore/ImportContact.swift index 0c194b40b9..3085e2fcd4 100644 --- a/TelegramCore/ImportContact.swift +++ b/TelegramCore/ImportContact.swift @@ -6,19 +6,19 @@ import SwiftSignalKit #endif -public func importContact(account:Account, firstName:String, lastName:String, phoneNumber:String) -> Signal { +public func importContact(account:Account, firstName: String, lastName: String, phoneNumber: String) -> Signal { let input = Api.InputContact.inputPhoneContact(clientId: 1, phone: phoneNumber, firstName: firstName, lastName: lastName) return account.network.request(Api.functions.contacts.importContacts(contacts: [input])) - |> map { Optional($0) } - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - return account.postbox.transaction { transaction -> PeerId? in - if let result = result { - switch result { + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> PeerId? in + if let result = result { + switch result { case let .importedContacts(_, _, _, users): if let first = users.first { let user = TelegramUser(user: first) @@ -33,11 +33,9 @@ public func importContact(account:Account, firstName:String, lastName:String, ph } return peerId } - - } } - return nil } + return nil + } } - } diff --git a/TelegramCore/InstantPage.swift b/TelegramCore/InstantPage.swift index 3007fc56c6..2d759ee293 100644 --- a/TelegramCore/InstantPage.swift +++ b/TelegramCore/InstantPage.swift @@ -467,7 +467,7 @@ public final class InstantPage: PostboxCoding, Equatable { } else { for (lhsKey, lhsValue) in lhs.media { if let media = rhs.media[lhsKey] { - if !lhsValue.isEqual(media) { + if !lhsValue.isEqual(to: media) { return false } } else { diff --git a/TelegramCore/JoinLink.swift b/TelegramCore/JoinLink.swift index 22d2950fb9..2e167fa7fe 100644 --- a/TelegramCore/JoinLink.swift +++ b/TelegramCore/JoinLink.swift @@ -25,69 +25,69 @@ public enum ExternalJoiningChatState { case invalidHash } -public func joinChatInteractively(with hash: String, account: Account) -> Signal { +public func joinChatInteractively(with hash: String, account: Account) -> Signal { return account.network.request(Api.functions.messages.importChatInvite(hash: hash)) - |> map { Optional($0) } - |> `catch` { _ in - return Signal.single(nil) - } - |> mapToSignal { updates -> Signal in - if let updates = updates { - account.stateManager.addUpdates(updates) - if let peerId = apiUpdatesGroups(updates).first?.peerId { - return account.postbox.multiplePeersView([peerId]) - |> filter { view in - return view.peers[peerId] != nil - } - |> take(1) - |> map { _ in - return peerId - } - |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + account.stateManager.addUpdates(updates) + if let peerId = apiUpdatesGroups(updates).first?.peerId { + return account.postbox.multiplePeersView([peerId]) + |> filter { view in + return view.peers[peerId] != nil } - return .single(nil) - } else { - return .single(nil) + |> take(1) + |> map { _ in + return peerId + } + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .single(nil)) } + return .single(nil) + } else { + return .single(nil) + } } } -public func joinLinkInformation(_ hash: String, account: Account) -> Signal { +public func joinLinkInformation(_ hash: String, account: Account) -> Signal { return account.network.request(Api.functions.messages.checkChatInvite(hash: hash)) - |> map { Optional($0) } - |> `catch` { _ in - return Signal.single(nil) - } - |> mapToSignal { (result) -> Signal in - if let result = result { - switch result { - case let .chatInvite(invite): - let photo: TelegramMediaImageRepresentation? - switch invite.photo { - case let .chatPhoto(photos): - if let resource = mediaResourceFromApiFileLocation(photos.photoSmall, size: nil) { - photo = TelegramMediaImageRepresentation(dimensions: CGSize(width: 100.0, height: 100.0), resource: resource) - } else { - photo = nil - } - case .chatPhotoEmpty: + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { (result) -> Signal in + if let result = result { + switch result { + case let .chatInvite(invite): + let photo: TelegramMediaImageRepresentation? + switch invite.photo { + case let .chatPhoto(photos): + if let resource = mediaResourceFromApiFileLocation(photos.photoSmall, size: nil) { + photo = TelegramMediaImageRepresentation(dimensions: CGSize(width: 100.0, height: 100.0), resource: resource) + } else { photo = nil - } - return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)}))) - case let .chatInviteAlready(chat: chat): - if let peer = parseTelegramGroupOrChannel(chat: chat) { - return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in - updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in - return updated - }) - - return .alreadyJoined(peer.id) + } + case .chatPhotoEmpty: + photo = nil + } + return .single(.invite(title: invite.title, photoRepresentation: photo, participantsCount: invite.participantsCount, participants: invite.participants?.map({TelegramUser(user: $0)}))) + case let .chatInviteAlready(chat: chat): + if let peer = parseTelegramGroupOrChannel(chat: chat) { + return account.postbox.transaction({ (transaction) -> ExternalJoiningChatState in + updatePeers(transaction: transaction, peers: [peer], update: { (previous, updated) -> Peer? in + return updated }) - } - return .single(.invalidHash) - } - } else { - return .single(.invalidHash) + + return .alreadyJoined(peer.id) + }) + } + return .single(.invalidHash) } + } else { + return .single(.invalidHash) + } } } diff --git a/TelegramCore/LoadMessagesIfNecessary.swift b/TelegramCore/LoadMessagesIfNecessary.swift index 76e62fd136..85b0f8132b 100644 --- a/TelegramCore/LoadMessagesIfNecessary.swift +++ b/TelegramCore/LoadMessagesIfNecessary.swift @@ -14,9 +14,7 @@ public enum GetMessagesStrategy { case cloud } -public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox, network:Network, strategy:GetMessagesStrategy = .cloud) -> Signal <[Message], Void> { - - +public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox, network:Network, strategy:GetMessagesStrategy = .cloud) -> Signal <[Message], NoError> { let postboxSignal = postbox.transaction { transaction -> ([Message], Set, SimpleDictionary) in var ids = messageIds @@ -44,7 +42,8 @@ public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox } if strategy == .cloud { - return postboxSignal |> mapToSignal { (existMessages, missingMessageIds, supportPeers) in + return postboxSignal + |> mapToSignal { (existMessages, missingMessageIds, supportPeers) in var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { @@ -76,8 +75,7 @@ public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox } } - return combineLatest(signals) |> mapToSignal { results -> Signal<[Message], Void> in - + return combineLatest(signals) |> mapToSignal { results -> Signal<[Message], NoError> in return postbox.transaction { transaction -> [Message] in for (messages, chats, users) in results { diff --git a/TelegramCore/LoadedPeerFromMessage.swift b/TelegramCore/LoadedPeerFromMessage.swift index 6d662431f9..64fe12820a 100644 --- a/TelegramCore/LoadedPeerFromMessage.swift +++ b/TelegramCore/LoadedPeerFromMessage.swift @@ -17,13 +17,13 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M let messageSignal: Signal? if messageId.peerId.namespace == Namespaces.Peer.CloudUser || messageId.peerId.namespace == Namespaces.Peer.CloudGroup { messageSignal = account.network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } } else if messageId.peerId.namespace == Namespaces.Peer.CloudChannel, let channelPeer = transaction.getPeer(messageId.peerId), let inputChannel = apiInputChannel(channelPeer) { messageSignal = account.network.request(Api.functions.channels.getMessages(channel: inputChannel, id: [Api.InputMessage.inputMessageID(id: messageId.id)])) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/LoadedStickerPack.swift b/TelegramCore/LoadedStickerPack.swift index 90563acfc2..574fa7dbd9 100644 --- a/TelegramCore/LoadedStickerPack.swift +++ b/TelegramCore/LoadedStickerPack.swift @@ -30,7 +30,7 @@ public enum LoadedStickerPack { func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference) -> Signal<(StickerPackCollectionInfo, [ItemCollectionItem])?, NoError> { return network.request(Api.functions.messages.getStickerSet(stickerset: reference.apiInputStickerSet)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/Localizations.swift b/TelegramCore/Localizations.swift index c420c5d009..8e31c04c7f 100644 --- a/TelegramCore/Localizations.swift +++ b/TelegramCore/Localizations.swift @@ -14,7 +14,7 @@ public func currentlySuggestedLocalization(network: Network, extractKeys: [Strin switch result { case let .config(config): if let suggestedLangCode = config.suggestedLangCode { - return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map { Optional($0) } + return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map(Optional.init) } else { return .single(nil) } diff --git a/TelegramCore/ManagedConsumePersonalMessagesActions.swift b/TelegramCore/ManagedConsumePersonalMessagesActions.swift index b6fc6f28d5..7a35bf8c2a 100644 --- a/TelegramCore/ManagedConsumePersonalMessagesActions.swift +++ b/TelegramCore/ManagedConsumePersonalMessagesActions.swift @@ -158,7 +158,7 @@ func managedConsumePersonalMessagesActions(postbox: Postbox, network: Network, s private func synchronizeConsumeMessageContents(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, id: MessageId) -> Signal { if id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup { return network.request(Api.functions.messages.readMessageContents(id: [id.id])) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/ManagedDeviceContacts.swift b/TelegramCore/ManagedDeviceContacts.swift index 09ca76a89d..67cca7a317 100644 --- a/TelegramCore/ManagedDeviceContacts.swift +++ b/TelegramCore/ManagedDeviceContacts.swift @@ -100,7 +100,7 @@ private enum ManagedDeviceContactsError { func managedDeviceContacts(postbox: Postbox, network: Network, deviceContacts: Signal<[DeviceContact], NoError>) -> Signal { #if os(iOS) && DEBUG - return .never() + //return .never() #endif let queue = Queue() @@ -224,19 +224,25 @@ func managedDeviceContacts(postbox: Postbox, network: Network, deviceContacts: S } } |> mapError { _ -> ManagedDeviceContactsError in return .generic } |> switchToLatest } - } |> mapError { _ -> ManagedDeviceContactsError in return .generic } |> switchToLatest + } + |> mapError { _ -> ManagedDeviceContactsError in + return .generic + } + |> switchToLatest return ((appliedDifference - |> `catch` { error -> Signal in - switch error { - case .done: - return .fail(NoError()) - case .generic: - return .fail(NoError()) - } - }) |> restart) |> `catch` { _ -> Signal in - return .complete() + |> `catch` { error -> Signal in + switch error { + case .done: + return .fail(Void()) + case .generic: + return .fail(Void()) } + }) + |> restart) + |> `catch` { _ -> Signal in + return .complete() + } } } diff --git a/TelegramCore/ManagedLocalizationUpdatesOperations.swift b/TelegramCore/ManagedLocalizationUpdatesOperations.swift index 4827730f7a..457061eca4 100644 --- a/TelegramCore/ManagedLocalizationUpdatesOperations.swift +++ b/TelegramCore/ManagedLocalizationUpdatesOperations.swift @@ -198,19 +198,22 @@ private func synchronizeLocalizationUpdates(transaction: Transaction, postbox: P } return ((poll - |> `catch` { error -> Signal in - switch error { - case .done: - return .fail(NoError()) - case .reset: - return postbox.transaction { transaction -> Signal in - let (code, _, _) = getLocalization(transaction) - return downoadAndApplyLocalization(postbox: postbox, network: network, languageCode: code) - } |> switchToLatest - } - }) |> restart) |> `catch` { _ -> Signal in - return .complete() + |> `catch` { error -> Signal in + switch error { + case .done: + return .fail(Void()) + case .reset: + return postbox.transaction { transaction -> Signal in + let (code, _, _) = getLocalization(transaction) + return downoadAndApplyLocalization(postbox: postbox, network: network, languageCode: code) + |> introduceError(Void.self) + } + |> introduceError(Void.self) + |> switchToLatest } + }) |> restart) |> `catch` { _ -> Signal in + return .complete() + } } func tryApplyingLanguageDifference(transaction: Transaction, difference: Api.LangPackDifference) -> Bool { diff --git a/TelegramCore/ManagedSecretChatOutgoingOperations.swift b/TelegramCore/ManagedSecretChatOutgoingOperations.swift index 4e7c30192b..1134c957a0 100644 --- a/TelegramCore/ManagedSecretChatOutgoingOperations.swift +++ b/TelegramCore/ManagedSecretChatOutgoingOperations.swift @@ -184,142 +184,148 @@ func managedSecretChatOutgoingOperations(postbox: Postbox, network: Network) -> private func initialHandshakeAccept(postbox: Postbox, network: Network, peerId: PeerId, accessHash: Int64, gA: MemoryBuffer, b: MemoryBuffer, tagLocalIndex: Int32) -> Signal { return validatedEncryptionConfig(postbox: postbox, network: network) - |> mapToSignal { config -> Signal in - var gValue: Int32 = config.g.byteSwapped - let g = Data(bytes: &gValue, count: 4) - let p = config.p.makeData() - - let bData = b.makeData() - - let gb = MTExp(g, bData, p)! - - var key = MTExp(gA.makeData(), bData, p)! - - if key.count > 256 { - key.count = 256 - } else { - while key.count < 256 { - key.insert(0, at: 0) - } + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let bData = b.makeData() + + let gb = MTExp(g, bData, p)! + + var key = MTExp(gA.makeData(), bData, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) } - - let keyHash = MTSha1(key)! - - var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) - } - - let result = network.request(Api.functions.messages.acceptEncryption(peer: .inputEncryptedChat(chatId: peerId.id, accessHash: accessHash), gB: Buffer(data: gb), keyFingerprint: keyFingerprint)) - - let response = result - |> map { result -> Api.EncryptedChat? in - return result - } - |> `catch` { error -> Signal in - return .single(nil) - } - - return response - |> mapToSignal { result -> Signal in - return postbox.transaction { transaction -> Void in - let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) - assert(removed) - if let state = transaction.getPeerChatState(peerId) as? SecretChatState { - var updatedState = state.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])).withUpdatedEmbeddedState(.basicLayer).withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) - var layer: SecretChatLayer? - switch updatedState.embeddedState { - case .terminated, .handshake: - break - case .basicLayer: - layer = .layer8 - case let .sequenceBasedLayer(sequenceState): - layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer - } - if let layer = layer { - updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: layer, actionGloballyUniqueId: arc4random64(), layerSupport: 46), state: updatedState) - } - transaction.setPeerChatState(peerId, state: updatedState) - if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { - updatePeers(transaction: transaction, peers: [peer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in - return updated - }) - } - } else { - assertionFailure() - } - } - } } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + let result = network.request(Api.functions.messages.acceptEncryption(peer: .inputEncryptedChat(chatId: peerId.id, accessHash: accessHash), gB: Buffer(data: gb), keyFingerprint: keyFingerprint)) + + let response = result + |> map { result -> Api.EncryptedChat? in + return result + } + |> `catch` { error -> Signal in + return .single(nil) + } + + return response + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Void in + let removed = transaction.operationLogRemoveEntry(peerId: peerId, tag: OperationLogTags.SecretOutgoing, tagLocalIndex: tagLocalIndex) + assert(removed) + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + var updatedState = state + updatedState = updatedState.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretIncomingDecrypted), baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: peerId, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil))) + updatedState = updatedState.withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) + + var layer: SecretChatLayer? + switch updatedState.embeddedState { + case .terminated, .handshake: + break + case .basicLayer: + layer = .layer8 + case let .sequenceBasedLayer(sequenceState): + layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer + } + if let layer = layer { + updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: .reportLayerSupport(layer: layer, actionGloballyUniqueId: arc4random64(), layerSupport: 46), state: updatedState) + } + transaction.setPeerChatState(peerId, state: updatedState) + if let peer = transaction.getPeer(peerId) as? TelegramSecretChat { + updatePeers(transaction: transaction, peers: [peer.withUpdatedEmbeddedState(updatedState.embeddedState.peerState)], update: { _, updated in + return updated + }) + } + } else { + assertionFailure() + } + } + } + } } private func pfsRequestKey(postbox: Postbox, network: Network, peerId: PeerId, layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, a: MemoryBuffer, tagLocalIndex: Int32, wasDelivered: Bool) -> Signal { - return validatedEncryptionConfig(postbox: postbox, network: network) - |> mapToSignal { config -> Signal in - var gValue: Int32 = config.g.byteSwapped - let g = Data(bytes: &gValue, count: 4) - let p = config.p.makeData() - - let aData = a.makeData() - let ga = MTExp(g, aData, p)! - - return postbox.transaction { transaction -> Signal in - if let state = transaction.getPeerChatState(peerId) as? SecretChatState { - switch state.embeddedState { - case let .sequenceBasedLayer(sequenceState): - if let rekeyState = sequenceState.rekeyState, case .requesting = rekeyState.data { - transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .requested(a: a, config: config)))))) - } - default: - break - } +return validatedEncryptionConfig(postbox: postbox, network: network) + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let aData = a.makeData() + let ga = MTExp(g, aData, p)! + + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if let rekeyState = sequenceState.rekeyState, case .requesting = rekeyState.data { + transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .requested(a: a, config: config)))))) + } + default: + break } - return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsRequestKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gA: MemoryBuffer(data: ga)), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) - } |> switchToLatest + } + return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsRequestKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gA: MemoryBuffer(data: ga)), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) + } + |> switchToLatest } } private func pfsAcceptKey(postbox: Postbox, network: Network, peerId: PeerId, layer: SecretChatSequenceBasedLayer, actionGloballyUniqueId: Int64, rekeySessionId: Int64, gA: MemoryBuffer, b: MemoryBuffer, tagLocalIndex: Int32, wasDelivered: Bool) -> Signal { return validatedEncryptionConfig(postbox: postbox, network: network) - |> mapToSignal { config -> Signal in - var gValue: Int32 = config.g.byteSwapped - let g = Data(bytes: &gValue, count: 4) - let p = config.p.makeData() - - let bData = b.makeData() - - let gb = MTExp(g, bData, p)! - - var key = MTExp(gA.makeData(), bData, p)! - - if key.count > 256 { - key.count = 256 - } else { - while key.count < 256 { - key.insert(0, at: 0) - } + |> mapToSignal { config -> Signal in + var gValue: Int32 = config.g.byteSwapped + let g = Data(bytes: &gValue, count: 4) + let p = config.p.makeData() + + let bData = b.makeData() + + let gb = MTExp(g, bData, p)! + + var key = MTExp(gA.makeData(), bData, p)! + + if key.count > 256 { + key.count = 256 + } else { + while key.count < 256 { + key.insert(0, at: 0) } - - let keyHash = MTSha1(key)! - - var keyFingerprint: Int64 = 0 - keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in - memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) - } - - return postbox.transaction { transaction -> Signal in - if let state = transaction.getPeerChatState(peerId) as? SecretChatState { - switch state.embeddedState { - case let .sequenceBasedLayer(sequenceState): - if let rekeyState = sequenceState.rekeyState, case .accepting = rekeyState.data { - transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .accepted(key: MemoryBuffer(data: key), keyFingerprint: keyFingerprint)))))) - } - default: - break + } + + let keyHash = MTSha1(key)! + + var keyFingerprint: Int64 = 0 + keyHash.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) + } + + return postbox.transaction { transaction -> Signal in + if let state = transaction.getPeerChatState(peerId) as? SecretChatState { + switch state.embeddedState { + case let .sequenceBasedLayer(sequenceState): + if let rekeyState = sequenceState.rekeyState, case .accepting = rekeyState.data { + transaction.setPeerChatState(peerId, state: state.withUpdatedEmbeddedState(.sequenceBasedLayer(sequenceState.withUpdatedRekeyState(SecretChatRekeySessionState(id: rekeyState.id, data: .accepted(key: MemoryBuffer(data: key), keyFingerprint: keyFingerprint)))))) } + default: + break } - return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsAcceptKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gB: MemoryBuffer(data: gb), keyFingerprint: keyFingerprint), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) - } |> switchToLatest + } + return sendServiceActionMessage(postbox: postbox, network: network, peerId: peerId, action: .pfsAcceptKey(layer: layer, actionGloballyUniqueId: actionGloballyUniqueId, rekeySessionId:rekeySessionId, gB: MemoryBuffer(data: gb), keyFingerprint: keyFingerprint), tagLocalIndex: tagLocalIndex, wasDelivered: wasDelivered) + } + |> switchToLatest } } @@ -341,7 +347,7 @@ private enum BoxedDecryptedMessage { buffer.appendInt32(46) if let sequenceInfo = sequenceInfo { - let inSeqNo = sequenceInfo.topReceivedOperationIndex * 2 + (role == .creator ? 0 : 1) + let inSeqNo = (sequenceInfo.topReceivedOperationIndex + 1) * 2 + (role == .creator ? 0 : 1) let outSeqNo = sequenceInfo.operationIndex * 2 + (role == .creator ? 1 : 0) buffer.appendInt32(inSeqNo) buffer.appendInt32(outSeqNo) @@ -361,7 +367,7 @@ private enum BoxedDecryptedMessage { buffer.appendInt32(73) if let sequenceInfo = sequenceInfo { - let inSeqNo = sequenceInfo.topReceivedOperationIndex * 2 + (role == .creator ? 0 : 1) + let inSeqNo = (sequenceInfo.topReceivedOperationIndex + 1) * 2 + (role == .creator ? 0 : 1) let outSeqNo = sequenceInfo.operationIndex * 2 + (role == .creator ? 1 : 0) buffer.appendInt32(inSeqNo) buffer.appendInt32(outSeqNo) @@ -1221,7 +1227,7 @@ private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer: private func requestTerminateSecretChat(postbox: Postbox, network: Network, peerId: PeerId, tagLocalIndex: Int32, reportSpam: Bool) -> Signal { return network.request(Api.functions.messages.discardEncryption(chatId: peerId.id)) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ in return .single(nil) } @@ -1237,7 +1243,7 @@ private func requestTerminateSecretChat(postbox: Postbox, network: Network, peer |> mapToSignal { peer -> Signal in if let peer = peer { return network.request(Api.functions.messages.reportEncryptedSpam(peer: Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash))) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift b/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift index 680f5c5908..bcd73cb45f 100644 --- a/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift +++ b/TelegramCore/ManagedSynchronizeConsumeMessageContentsOperations.swift @@ -116,7 +116,7 @@ func managedSynchronizeConsumeMessageContentOperations(postbox: Postbox, network private func synchronizeConsumeMessageContents(transaction: Transaction, network: Network, stateManager: AccountStateManager, peerId: PeerId, operation: SynchronizeConsumeMessageContentsOperation) -> Signal { if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { return network.request(Api.functions.messages.readMessageContents(id: operation.messageIds.map { $0.id })) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -132,7 +132,7 @@ private func synchronizeConsumeMessageContents(transaction: Transaction, network } else if peerId.namespace == Namespaces.Peer.CloudChannel { if let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) { return network.request(Api.functions.channels.readMessageContents(channel: inputChannel, id: operation.messageIds.map { $0.id })) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/Network.swift b/TelegramCore/Network.swift index f16999a0e2..e8fa18e5c0 100644 --- a/TelegramCore/Network.swift +++ b/TelegramCore/Network.swift @@ -550,7 +550,7 @@ public final class Network: NSObject, MTRequestMessageServiceDelegate { context.add(NetworkHelper(requestPublicKeys: { [weak self] id in if let strongSelf = self { return strongSelf.request(Api.functions.help.getCdnConfig()) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } diff --git a/TelegramCore/PeerAdmins.swift b/TelegramCore/PeerAdmins.swift index 10cff39c98..dc17765cf8 100644 --- a/TelegramCore/PeerAdmins.swift +++ b/TelegramCore/PeerAdmins.swift @@ -14,40 +14,40 @@ public enum GroupManagementType { case unrestricted } -public func updateGroupManagementType(account: Account, peerId: PeerId, type: GroupManagementType) -> Signal { - return account.postbox.transaction { transaction -> Signal in +public enum UpdateGroupManagementTypeError { + case generic +} + +public func updateGroupManagementType(account: Account, peerId: PeerId, type: GroupManagementType) -> Signal { + return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId) { if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { return account.network.request(Api.functions.channels.toggleInvites(channel: inputChannel, enabled: type == .unrestricted ? .boolTrue : .boolFalse)) - |> map { Optional($0) } - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - if let result = result { - account.stateManager.addUpdates(result) - } - return .complete() - } + |> mapError { _ -> UpdateGroupManagementTypeError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } } else if let group = peer as? TelegramGroup { return account.network.request(Api.functions.messages.toggleChatAdmins(chatId: group.id.id, enabled: type == .restrictedToAdmins ? .boolTrue : .boolFalse)) - |> map { Optional($0) } - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - if let result = result { - account.stateManager.addUpdates(result) - } - return .complete() - } + |> mapError { _ -> UpdateGroupManagementTypeError in + return .generic + } + |> mapToSignal { result -> Signal in + account.stateManager.addUpdates(result) + return .complete() + } } else { return .complete() } } else { return .complete() } - } |> switchToLatest + } + |> introduceError(UpdateGroupManagementTypeError.self) + |> switchToLatest } public enum RemovePeerAdminError { diff --git a/TelegramCore/PendingMessageManager.swift b/TelegramCore/PendingMessageManager.swift index 2087e43cf9..6b40524410 100644 --- a/TelegramCore/PendingMessageManager.swift +++ b/TelegramCore/PendingMessageManager.swift @@ -267,7 +267,7 @@ public final class PendingMessageManager { continue } - let contentUploadSignal = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, message: message) + let contentUploadSignal = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, message: message) if strongSelf.canBeginUploadingMessage(id: message.id) { strongSelf.beginUploadingMessage(messageContext: messageContext, id: message.id, groupId: message.groupingKey, uploadSignal: contentUploadSignal) @@ -420,9 +420,11 @@ public final class PendingMessageManager { }) } return modify - |> mapToSignal { _ in return .complete() } + |> mapToSignal { _ in + return .complete() + } } - return .fail(Void()) + return .complete() }).start(next: { [weak self] next in if let strongSelf = self { assert(strongSelf.queue.isCurrent()) @@ -887,7 +889,8 @@ public final class PendingMessageManager { } private func applySentGroupMessages(postbox: Postbox, stateManager: AccountStateManager, messages: [Message], result: Api.Updates) -> Signal { - return applyUpdateGroupMessages(postbox: postbox, stateManager: stateManager, messages: messages, result: result) |> afterDisposed { [weak self] in + return applyUpdateGroupMessages(postbox: postbox, stateManager: stateManager, messages: messages, result: result) + |> afterDisposed { [weak self] in if let strongSelf = self { strongSelf.queue.async { if let peerId = messages.first?.id.peerId, let context = strongSelf.peerSummaryContexts[peerId] { diff --git a/TelegramCore/PendingMessageUploadedContent.swift b/TelegramCore/PendingMessageUploadedContent.swift index 3c69d40f64..f7c4eaa116 100644 --- a/TelegramCore/PendingMessageUploadedContent.swift +++ b/TelegramCore/PendingMessageUploadedContent.swift @@ -245,7 +245,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans } } } - let transform: Signal + let transform: Signal if let transformOutgoingMessageMedia = transformOutgoingMessageMedia, let messageId = messageId, !alreadyTransformed { transform = .single(.pending) |> then( @@ -506,7 +506,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili } } - let transform: Signal + let transform: Signal if let transformOutgoingMessageMedia = transformOutgoingMessageMedia, let messageId = messageId, !alreadyTransformed { transform = .single(.pending) |> then(transformOutgoingMessageMedia(postbox, network, .standalone(media: file), false) diff --git a/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift b/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift index 060aa31d36..1a6ff11652 100644 --- a/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift +++ b/TelegramCore/ProcessSecretChatIncomingDecryptedOperations.swift @@ -60,7 +60,6 @@ struct SecretChatOperationProcessResult { func processSecretChatIncomingDecryptedOperations(mediaBox: MediaBox, transaction: Transaction, peerId: PeerId) -> SecretChatOperationProcessResult { if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat { var removeTagLocalIndices: [Int32] = [] - var addedDecryptedOperations = false var updatedState = state var couldNotResendRequestedMessages = false var maxAcknowledgedCanonicalOperationIndex: Int32? diff --git a/TelegramCore/RateCall.swift b/TelegramCore/RateCall.swift index a9a5e649c4..26ec289c23 100644 --- a/TelegramCore/RateCall.swift +++ b/TelegramCore/RateCall.swift @@ -9,6 +9,8 @@ import Foundation import SwiftSignalKit #endif -public func rateCall(account:Account, report:ReportCallRating, starsCount:Int32, comment:String = "") -> Signal { - return account.network.request(Api.functions.phone.setCallRating(peer: Api.InputPhoneCall.inputPhoneCall(id: report.id, accessHash: report.accessHash), rating: starsCount, comment: comment)) |> retryRequest |> map {_ in} +public func rateCall(account: Account, report: ReportCallRating, starsCount: Int32, comment: String = "") -> Signal { + return account.network.request(Api.functions.phone.setCallRating(peer: Api.InputPhoneCall.inputPhoneCall(id: report.id, accessHash: report.accessHash), rating: starsCount, comment: comment)) + |> retryRequest + |> map { _ in } } diff --git a/TelegramCore/RecentMediaItem.swift b/TelegramCore/RecentMediaItem.swift index 92264eed2c..30bd5cc1b6 100644 --- a/TelegramCore/RecentMediaItem.swift +++ b/TelegramCore/RecentMediaItem.swift @@ -45,6 +45,6 @@ public final class RecentMediaItem: OrderedItemListEntryContents, Equatable { } public static func ==(lhs: RecentMediaItem, rhs: RecentMediaItem) -> Bool { - return lhs.media.isEqual(rhs.media) + return lhs.media.isEqual(to: rhs.media) } } diff --git a/TelegramCore/RecentWebSessions.swift b/TelegramCore/RecentWebSessions.swift index d11f884ce9..dda450af43 100644 --- a/TelegramCore/RecentWebSessions.swift +++ b/TelegramCore/RecentWebSessions.swift @@ -48,20 +48,24 @@ public func webSessions(network: Network) -> Signal<([WebAuthorization], [PeerId } -public func terminateWebSession(network: Network, hash: Int64) -> Signal { - return network.request(Api.functions.account.resetWebAuthorization(hash: hash)) |> retryRequest |> map { result in +public func terminateWebSession(network: Network, hash: Int64) -> Signal { + return network.request(Api.functions.account.resetWebAuthorization(hash: hash)) + |> retryRequest + |> map { result in switch result { - case .boolFalse: - return false - case .boolTrue: - return true + case .boolFalse: + return false + case .boolTrue: + return true } } } -public func terminateAllWebSessions(network: Network) -> Signal { - return network.request(Api.functions.account.resetWebAuthorizations()) |> retryRequest |> map {_ in} +public func terminateAllWebSessions(network: Network) -> Signal { + return network.request(Api.functions.account.resetWebAuthorizations()) + |> retryRequest + |> map { _ in } } diff --git a/TelegramCore/RemovePeerChat.swift b/TelegramCore/RemovePeerChat.swift index bf7660a802..ddc627934f 100644 --- a/TelegramCore/RemovePeerChat.swift +++ b/TelegramCore/RemovePeerChat.swift @@ -37,5 +37,6 @@ public func removePeerChat(postbox: Postbox, peerId: PeerId, reportChatSpam: Boo transaction.updatePeerChatListInclusion(peerId, inclusion: .never) } } + transaction.removeOrderedItemListItem(collectionId: Namespaces.OrderedItemList.RecentlySearchedPeerIds, itemId: RecentPeerItemId(peerId).rawValue) } } diff --git a/TelegramCore/ReportPeer.swift b/TelegramCore/ReportPeer.swift index afc4cdd9f0..0e0c7a1789 100644 --- a/TelegramCore/ReportPeer.swift +++ b/TelegramCore/ReportPeer.swift @@ -14,7 +14,7 @@ public func reportPeer(account: Account, peerId: PeerId) -> Signal map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -37,7 +37,7 @@ public func reportPeer(account: Account, peerId: PeerId) -> Signal map { Optional($0) } + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } @@ -92,7 +92,13 @@ private extension ReportReason { public func reportPeer(account: Account, peerId: PeerId, reason: ReportReason) -> Signal { return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { - return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason)) |> mapError {_ in} |> map {_ in} + return account.network.request(Api.functions.account.reportPeer(peer: inputPeer, reason: reason.apiReason)) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } } else { return .complete() } @@ -125,7 +131,13 @@ public func reportPeerMessages(account: Account, messageIds: [MessageId], reason public func reportSupergroupPeer(account: Account, peerId: PeerId, memberId: PeerId, messageIds: [MessageId]) -> Signal { return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputPeer = apiInputChannel(peer), let memberPeer = transaction.getPeer(memberId), let inputMember = apiInputUser(memberPeer) { - return account.network.request(Api.functions.channels.reportSpam(channel: inputPeer, userId: inputMember, id: messageIds.map({$0.id}))) |> mapError {_ in} |> map {_ in} + return account.network.request(Api.functions.channels.reportSpam(channel: inputPeer, userId: inputMember, id: messageIds.map({$0.id}))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { _ -> Signal in + return .complete() + } } else { return .complete() } diff --git a/TelegramCore/RequestMessageActionCallback.swift b/TelegramCore/RequestMessageActionCallback.swift index b97bac49d4..b774a01036 100644 --- a/TelegramCore/RequestMessageActionCallback.swift +++ b/TelegramCore/RequestMessageActionCallback.swift @@ -31,25 +31,29 @@ public func requestMessageActionCallback(account: Account, messageId: MessageId, flags |= Int32(1 << 1) } return account.network.request(Api.functions.messages.getBotCallbackAnswer(flags: flags, peer: inputPeer, msgId: messageId.id, data: dataBuffer)) - |> mapError {_ in} - |> map { result -> MessageActionCallbackResult in - //messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - - switch result { - case let .botCallbackAnswer(flags, message, url, cacheTime): - if let message = message { - if (flags & (1 << 1)) != 0 { - return .alert(message) - } else { - return .toast(message) - } - } else if let url = url { - return .url(url) - } else { - return .none - } - } + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> MessageActionCallbackResult in + guard let result = result else { + return .none } + switch result { + case let .botCallbackAnswer(flags, message, url, cacheTime): + if let message = message { + if (flags & (1 << 1)) != 0 { + return .alert(message) + } else { + return .toast(message) + } + } else if let url = url { + return .url(url) + } else { + return .none + } + } + } } else { return .single(.none) } diff --git a/TelegramCore/RequestSecureIdForm.swift b/TelegramCore/RequestSecureIdForm.swift index eaf4161fd9..7bfaf3d234 100644 --- a/TelegramCore/RequestSecureIdForm.swift +++ b/TelegramCore/RequestSecureIdForm.swift @@ -15,18 +15,18 @@ public enum RequestSecureIdFormError { case versionOutdated } -private func parseSecureValueType(_ type: Api.SecureValueType, selfie: Bool) -> SecureIdRequestedFormField { +private func parseSecureValueType(_ type: Api.SecureValueType, selfie: Bool, translation: Bool) -> SecureIdRequestedFormField { switch type { case .secureValueTypePersonalDetails: return .personalDetails case .secureValueTypePassport: - return .passport(selfie: selfie) + return .passport(selfie: selfie, translation: translation) case .secureValueTypeInternalPassport: - return .internalPassport(selfie: selfie) + return .internalPassport(selfie: selfie, translation: translation) case .secureValueTypeDriverLicense: - return .driversLicense(selfie: selfie) + return .driversLicense(selfie: selfie, translation: translation) case .secureValueTypeIdentityCard: - return .idCard(selfie: selfie) + return .idCard(selfie: selfie, translation: translation) case .secureValueTypeAddress: return .address case .secureValueTypeUtilityBill: @@ -59,9 +59,11 @@ struct ParsedSecureValue { func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, errors: [Api.SecureValueError]) -> ParsedSecureValue? { switch value { - case let .secureValue(_, type, data, frontSide, reverseSide, selfie, files, plainData, hash): + case let .secureValue(_, type, data, frontSide, reverseSide, selfie, translation, files, plainData, hash): let parsedFileReferences = files.flatMap { $0.compactMap(SecureIdFileReference.init) } ?? [] let parsedFiles = parsedFileReferences.map(SecureIdVerificationDocumentReference.remote) + let parsedTranslationReferences = translation.flatMap { $0.compactMap(SecureIdFileReference.init) } ?? [] + let parsedTranslations = parsedTranslationReferences.map(SecureIdVerificationDocumentReference.remote) let parsedFrontSide = frontSide.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) let parsedBackSide = reverseSide.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) let parsedSelfie = selfie.flatMap(SecureIdFileReference.init).flatMap(SecureIdVerificationDocumentReference.remote) @@ -69,6 +71,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er let decryptedData: Data? let encryptedMetadata: SecureIdEncryptedValueMetadata? var parsedFileMetadata: [SecureIdEncryptedValueFileMetadata] = [] + var parsedTranslationMetadata: [SecureIdEncryptedValueFileMetadata] = [] var parsedSelfieMetadata: SecureIdEncryptedValueFileMetadata? var parsedFrontSideMetadata: SecureIdEncryptedValueFileMetadata? var parsedBackSideMetadata: SecureIdEncryptedValueFileMetadata? @@ -96,6 +99,12 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er } parsedFileMetadata.append(SecureIdEncryptedValueFileMetadata(hash: file.fileHash, secret: fileSecret)) } + for file in parsedTranslationReferences { + guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: file.fileHash, encryptedSecret: file.encryptedSecret) else { + return nil + } + parsedTranslationMetadata.append(SecureIdEncryptedValueFileMetadata(hash: file.fileHash, secret: fileSecret)) + } if let parsedSelfie = selfie.flatMap(SecureIdFileReference.init) { guard let fileSecret = decryptedSecureIdFileSecret(context: context, fileHash: parsedSelfie.fileHash, encryptedSecret: parsedSelfie.encryptedSecret) else { return nil @@ -133,7 +142,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { return nil } - guard let passport = SecureIdPassportValue(dict: dict, fileReferences: parsedFiles, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { + guard let passport = SecureIdPassportValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { return nil } value = .passport(passport) @@ -141,7 +150,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { return nil } - guard let internalPassport = SecureIdInternalPassportValue(dict: dict, fileReferences: parsedFiles, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { + guard let internalPassport = SecureIdInternalPassportValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide) else { return nil } value = .internalPassport(internalPassport) @@ -149,7 +158,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { return nil } - guard let driversLicense = SecureIdDriversLicenseValue(dict: dict, fileReferences: parsedFiles, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { + guard let driversLicense = SecureIdDriversLicenseValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { return nil } value = .driversLicense(driversLicense) @@ -157,7 +166,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er guard let dict = (try? JSONSerialization.jsonObject(with: decryptedData ?? Data(), options: [])) as? [String: Any] else { return nil } - guard let idCard = SecureIdIDCardValue(dict: dict, fileReferences: parsedFiles, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { + guard let idCard = SecureIdIDCardValue(dict: dict, fileReferences: parsedFiles, translations: parsedTranslations, selfieDocument: parsedSelfie, frontSideDocument: parsedFrontSide, backSideDocument: parsedBackSide) else { return nil } value = .idCard(idCard) @@ -216,7 +225,7 @@ func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue, er } } - return ParsedSecureValue(valueWithContext: SecureIdValueWithContext(value: value, errors: parseSecureIdValueContentErrors(dataHash: contentsId, fileHashes: Set(parsedFileMetadata.map { $0.hash }), selfieHash: parsedSelfieMetadata?.hash, frontSideHash: parsedFrontSideMetadata?.hash, backSideHash: parsedBackSideMetadata?.hash, errors: errors), files: parsedFileMetadata, selfie: parsedSelfieMetadata, frontSide: parsedFrontSideMetadata, backSide: parsedBackSideMetadata, encryptedMetadata: encryptedMetadata, opaqueHash: hash.makeData())) + return ParsedSecureValue(valueWithContext: SecureIdValueWithContext(value: value, errors: parseSecureIdValueContentErrors(dataHash: contentsId, fileHashes: Set(parsedFileMetadata.map { $0.hash }), selfieHash: parsedSelfieMetadata?.hash, frontSideHash: parsedFrontSideMetadata?.hash, backSideHash: parsedBackSideMetadata?.hash, errors: errors), files: parsedFileMetadata, translations: parsedTranslationMetadata, selfie: parsedSelfieMetadata, frontSide: parsedFrontSideMetadata, backSide: parsedBackSideMetadata, encryptedMetadata: encryptedMetadata, opaqueHash: hash.makeData())) } } @@ -260,8 +269,22 @@ public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: Peer return updated }) - return EncryptedSecureIdForm(peerId: peerId, requestedFields: requiredTypes.map { - return parseSecureValueType($0, selfie: (flags & 1 << 1) != 0) + return EncryptedSecureIdForm(peerId: peerId, requestedFields: requiredTypes.map { requiredType in + //flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; + switch requiredType { + case let .secureRequiredType(flags, type): + return parseSecureValueType(type, selfie: (flags & 1 << 1) != 0, translation: (flags & 1 << 2) != 0) + case let .secureRequiredTypeOneOf(types): + let parsedInnerTypes = types.compactMap { innerType -> SecureIdRequestedFormField? in + switch innerType { + case let .secureRequiredType(flags, type): + return parseSecureValueType(type, selfie: (flags & 1 << 1) != 0, translation: (flags & 1 << 2) != 0) + case .secureRequiredTypeOneOf: + return nil + } + } + return .oneOf(parsedInnerTypes) + } }, termsUrl: termsUrl, encryptedValues: values, errors: errors) } } |> mapError { _ in return RequestSecureIdFormError.generic } diff --git a/TelegramCore/RequestUserPhotos.swift b/TelegramCore/RequestUserPhotos.swift index 86728eb601..15d9c63531 100644 --- a/TelegramCore/RequestUserPhotos.swift +++ b/TelegramCore/RequestUserPhotos.swift @@ -18,126 +18,128 @@ public struct TelegramPeerPhoto { public let totalCount:Int } -public func requestPeerPhotos(account:Account, peerId:PeerId) -> Signal<[TelegramPeerPhoto], Void> { +public func requestPeerPhotos(account:Account, peerId: PeerId) -> Signal<[TelegramPeerPhoto], NoError> { return account.postbox.transaction{ transaction -> Peer? in return transaction.getPeer(peerId) - } |> mapToSignal { peer -> Signal<[TelegramPeerPhoto], Void> in + } + |> mapToSignal { peer -> Signal<[TelegramPeerPhoto], NoError> in if let peer = peer as? TelegramUser, let inputUser = apiInputUser(peer) { return account.network.request(Api.functions.photos.getUserPhotos(userId: inputUser, offset: 0, maxId: 0, limit: 100)) - |> map {Optional($0)} - |> mapError {_ in} - |> `catch` { - return Signal.single(nil) - } |> map { result -> [TelegramPeerPhoto] in - - if let result = result { - let totalCount:Int - let photos:[Api.Photo] - switch result { - case let .photos(data): - photos = data.photos - totalCount = photos.count - case let .photosSlice(data): - photos = data.photos - totalCount = Int(data.count) - } - - var images:[TelegramPeerPhoto] = [] - for i in 0 ..< photos.count { - let photo = photos[i] - let image:TelegramMediaImage - let reference: TelegramMediaImageReference - switch photo { - case let .photo(data): - reference = .cloud(imageId: data.id, accessHash: data.accessHash, fileReference: data.fileReference.makeData()) - image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: data.id), representations: telegramMediaImageRepresentationsFromApiSizes(data.sizes), reference: reference, partialReference: nil) - case let .photoEmpty(id: id): - reference = .cloud(imageId: id, accessHash: 0, fileReference: nil) - image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: [], reference: reference, partialReference: nil) - } - images.append(TelegramPeerPhoto(image: image, reference: reference, index: i, totalCount: totalCount)) - } - - return images - } else { - return [] + |> map {Optional($0)} + |> mapError {_ in} + |> `catch` { _ -> Signal in + return .single(nil) + } + |> map { result -> [TelegramPeerPhoto] in + + if let result = result { + let totalCount:Int + let photos:[Api.Photo] + switch result { + case let .photos(data): + photos = data.photos + totalCount = photos.count + case let .photosSlice(data): + photos = data.photos + totalCount = Int(data.count) } + + var images:[TelegramPeerPhoto] = [] + for i in 0 ..< photos.count { + let photo = photos[i] + let image:TelegramMediaImage + let reference: TelegramMediaImageReference + switch photo { + case let .photo(data): + reference = .cloud(imageId: data.id, accessHash: data.accessHash, fileReference: data.fileReference.makeData()) + image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: data.id), representations: telegramMediaImageRepresentationsFromApiSizes(data.sizes), reference: reference, partialReference: nil) + case let .photoEmpty(id: id): + reference = .cloud(imageId: id, accessHash: 0, fileReference: nil) + image = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: id), representations: [], reference: reference, partialReference: nil) + } + images.append(TelegramPeerPhoto(image: image, reference: reference, index: i, totalCount: totalCount)) + } + + return images + } else { + return [] + } } } else if let peer = peer, let inputPeer = apiInputPeer(peer) { - return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0)) |> map {Optional($0)} - |> mapError {_ in} - |> `catch` { - return Signal.single(nil) - } |> mapToSignal { result -> Signal<[TelegramPeerPhoto], Void> in - - if let result = result { - let messages: [Api.Message] - let chats: [Api.Chat] - let users: [Api.User] - switch result { - case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .messages(apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let.messagesSlice(_, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case .messagesNotModified: - messages = [] - chats = [] - users = [] - } - - return account.postbox.transaction { transaction -> [Message] in - var peers: [PeerId: Peer] = [:] - - for user in users { - if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { - peers[user.id] = user - } - } - - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers[groupOrChannel.id] = groupOrChannel - } - } - - var renderedMessages: [Message] = [] - for message in messages { - if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { - renderedMessages.append(renderedMessage) - } - } - - return renderedMessages - } |> map { messages -> [TelegramPeerPhoto] in - var photos:[TelegramPeerPhoto] = [] - var index:Int = 0 - for message in messages { - if let media = message.media.first as? TelegramMediaAction { - switch media.action { - case let .photoUpdated(image): - if let image = image { - photos.append(TelegramPeerPhoto(image: image, reference: nil, index: index, totalCount: messages.count)) - } - default: - break - } - } - index += 1 - } - return photos - } - - } else { - return .single([]) + return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: "", fromId: nil, filter: .inputMessagesFilterChatPhotos, minDate: 0, maxDate: 0, offsetId: 0, addOffset: 0, limit: 1000, maxId: 0, minId: 0, hash: 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal<[TelegramPeerPhoto], NoError> in + if let result = result { + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + switch result { + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let.messagesSlice(_, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] } + + return account.postbox.transaction { transaction -> [Message] in + var peers: [PeerId: Peer] = [:] + + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user + } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } + + var renderedMessages: [Message] = [] + for message in messages { + if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + renderedMessages.append(renderedMessage) + } + } + + return renderedMessages + } |> map { messages -> [TelegramPeerPhoto] in + var photos:[TelegramPeerPhoto] = [] + var index:Int = 0 + for message in messages { + if let media = message.media.first as? TelegramMediaAction { + switch media.action { + case let .photoUpdated(image): + if let image = image { + photos.append(TelegramPeerPhoto(image: image, reference: nil, index: index, totalCount: messages.count)) + } + default: + break + } + } + index += 1 + } + return photos + } + + } else { + return .single([]) + } } } else { return .single([]) diff --git a/TelegramCore/ResolvePeerByName.swift b/TelegramCore/ResolvePeerByName.swift index 0b54b09f56..b990fe8b62 100644 --- a/TelegramCore/ResolvePeerByName.swift +++ b/TelegramCore/ResolvePeerByName.swift @@ -75,46 +75,47 @@ public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = return .single(cachedEntry.peerId) } else { return account.network.request(Api.functions.contacts.resolveUsername(username: normalizedName)) - |> mapError { _ -> NoError in - return NoError() - } - |> mapToSignal { result -> Signal in - return account.postbox.transaction { transaction -> PeerId? in - var peerId: PeerId? = nil - - switch result { - case let .resolvedPeer(apiPeer, chats, users): - var peers: [PeerId: Peer] = [:] - - for user in users { - if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { - peers[user.id] = user - } - } - - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers[groupOrChannel.id] = groupOrChannel - } - } + |> mapError { _ -> Void in + return Void() + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> PeerId? in + var peerId: PeerId? = nil + + switch result { + case let .resolvedPeer(apiPeer, chats, users): + var peers: [PeerId: Peer] = [:] - if let peer = peers[apiPeer.peerId] { - peerId = peer.id - - updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated -> Peer in - return updated - }) + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user } - } + } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + } + } - let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp), collectionSpec: resolvedByNamePeersCollectionSpec) - return peerId + if let peer = peers[apiPeer.peerId] { + peerId = peer.id + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated -> Peer in + return updated + }) + } } + + let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.resolvedByNamePeers, key: CachedResolvedByNamePeer.key(name: normalizedName)), entry: CachedResolvedByNamePeer(peerId: peerId, timestamp: timestamp), collectionSpec: resolvedByNamePeersCollectionSpec) + return peerId } - |> `catch` { _ -> Signal in - return .single(nil) - } + |> introduceError(Void.self) + } + |> `catch` { _ -> Signal in + return .single(nil) + } } } } diff --git a/TelegramCore/SaveSecureIdValue.swift b/TelegramCore/SaveSecureIdValue.swift index bb91889cc7..f5af406dcd 100644 --- a/TelegramCore/SaveSecureIdValue.swift +++ b/TelegramCore/SaveSecureIdValue.swift @@ -100,6 +100,7 @@ private struct InputSecureIdValueData { let type: Api.SecureValueType let dict: [String: Any]? let fileReferences: [SecureIdVerificationDocumentReference] + let translationReferences: [SecureIdVerificationDocumentReference] let frontSideReference: SecureIdVerificationDocumentReference? let backSideReference: SecureIdVerificationDocumentReference? let selfieReference: SecureIdVerificationDocumentReference? @@ -110,41 +111,41 @@ private func inputSecureIdValueData(value: SecureIdValue) -> InputSecureIdValueD switch value { case let .personalDetails(personalDetails): let (dict, fileReferences) = personalDetails.serialize() - return InputSecureIdValueData(type: .secureValueTypePersonalDetails, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypePersonalDetails, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .passport(passport): - let (dict, fileReferences, selfieReference, frontSideReference) = passport.serialize() - return InputSecureIdValueData(type: .secureValueTypePassport, dict: dict, fileReferences: fileReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference) = passport.serialize() + return InputSecureIdValueData(type: .secureValueTypePassport, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) case let .internalPassport(internalPassport): - let (dict, fileReferences, selfieReference, frontSideReference) = internalPassport.serialize() - return InputSecureIdValueData(type: .secureValueTypeInternalPassport, dict: dict, fileReferences: fileReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference) = internalPassport.serialize() + return InputSecureIdValueData(type: .secureValueTypeInternalPassport, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: nil, selfieReference: selfieReference, publicData: nil) case let .driversLicense(driversLicense): - let (dict, fileReferences, selfieReference, frontSideReference, backSideReference) = driversLicense.serialize() - return InputSecureIdValueData(type: .secureValueTypeDriverLicense, dict: dict, fileReferences: fileReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference, backSideReference) = driversLicense.serialize() + return InputSecureIdValueData(type: .secureValueTypeDriverLicense, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) case let .idCard(idCard): - let (dict, fileReferences, selfieReference, frontSideReference, backSideReference) = idCard.serialize() - return InputSecureIdValueData(type: .secureValueTypeIdentityCard, dict: dict, fileReferences: fileReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) + let (dict, fileReferences, translationReferences, selfieReference, frontSideReference, backSideReference) = idCard.serialize() + return InputSecureIdValueData(type: .secureValueTypeIdentityCard, dict: dict, fileReferences: fileReferences, translationReferences: translationReferences, frontSideReference: frontSideReference, backSideReference: backSideReference, selfieReference: selfieReference, publicData: nil) case let .address(address): let (dict, fileReferences) = address.serialize() - return InputSecureIdValueData(type: .secureValueTypeAddress, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypeAddress, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .passportRegistration(passportRegistration): let (dict, fileReferences) = passportRegistration.serialize() - return InputSecureIdValueData(type: .secureValueTypePassportRegistration, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypePassportRegistration, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .temporaryRegistration(temporaryRegistration): let (dict, fileReferences) = temporaryRegistration.serialize() - return InputSecureIdValueData(type: .secureValueTypeTemporaryRegistration, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypeTemporaryRegistration, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .utilityBill(utilityBill): let (dict, fileReferences) = utilityBill.serialize() - return InputSecureIdValueData(type: .secureValueTypeUtilityBill, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypeUtilityBill, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .bankStatement(bankStatement): let (dict, fileReferences) = bankStatement.serialize() - return InputSecureIdValueData(type: .secureValueTypeBankStatement, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypeBankStatement, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .rentalAgreement(rentalAgreement): let (dict, fileReferences) = rentalAgreement.serialize() - return InputSecureIdValueData(type: .secureValueTypeRentalAgreement, dict: dict, fileReferences: fileReferences, frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) + return InputSecureIdValueData(type: .secureValueTypeRentalAgreement, dict: dict, fileReferences: fileReferences, translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: nil) case let .phone(phone): - return InputSecureIdValueData(type: .secureValueTypePhone, dict: nil, fileReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainPhone(phone: phone.phone)) + return InputSecureIdValueData(type: .secureValueTypePhone, dict: nil, fileReferences: [], translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainPhone(phone: phone.phone)) case let .email(email): - return InputSecureIdValueData(type: .secureValueTypeEmail, dict: nil, fileReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainEmail(email: email.email)) + return InputSecureIdValueData(type: .secureValueTypeEmail, dict: nil, fileReferences: [], translationReferences: [], frontSideReference: nil, backSideReference: nil, selfieReference: nil, publicData: .securePlainEmail(email: email.email)) } } @@ -181,6 +182,7 @@ private func makeInputSecureValue(context: SecureIdAccessContext, value: SecureI var flags: Int32 = 0 let files = inputData.fileReferences.map(apiInputSecretFile) + let translations = inputData.translationReferences.flatMap(apiInputSecretFile) if secureData != nil { flags |= 1 << 0 @@ -197,11 +199,14 @@ private func makeInputSecureValue(context: SecureIdAccessContext, value: SecureI if !files.isEmpty { flags |= 1 << 4 } + if !translations.isEmpty { + flags |= 1 << 6 + } if inputData.publicData != nil { flags |= 1 << 5 } - return Api.InputSecureValue.inputSecureValue(flags: flags, type: inputData.type, data: secureData, frontSide: inputData.frontSideReference.flatMap(apiInputSecretFile), reverseSide: inputData.backSideReference.flatMap(apiInputSecretFile), selfie: inputData.selfieReference.flatMap(apiInputSecretFile), files: files, plainData: inputData.publicData) + return Api.InputSecureValue.inputSecureValue(flags: flags, type: inputData.type, data: secureData, frontSide: inputData.frontSideReference.flatMap(apiInputSecretFile), reverseSide: inputData.backSideReference.flatMap(apiInputSecretFile), selfie: inputData.selfieReference.flatMap(apiInputSecretFile), translation: translations, files: files, plainData: inputData.publicData) } public func saveSecureIdValue(postbox: Postbox, network: Network, context: SecureIdAccessContext, value: SecureIdValue, uploadedFiles: [Data: Data]) -> Signal { @@ -268,19 +273,19 @@ public func dropSecureId(network: Network, currentPassword: String) -> Signal mapToSignal { authData -> Signal in - let currentPasswordHash: Data - if let currentPasswordDerivation = authData.currentPasswordDerivation { - let passwordHash = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation) - if let passwordHash = passwordHash { - currentPasswordHash = passwordHash + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) + if let kdfResult = kdfResult { + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) } else { return .fail(.generic) } } else { - currentPasswordHash = Data() + checkPassword = .inputCheckPasswordEmpty } - let settings = network.request(Api.functions.account.getPasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false) + let settings = network.request(Api.functions.account.getPasswordSettings(password: checkPassword), automaticFloodWait: false) |> mapError { error in return AuthorizationPasswordVerificationError.generic } @@ -291,7 +296,7 @@ public func dropSecureId(network: Network, currentPassword: String) -> Signal map { _ in } |> mapError { _ in return AuthorizationPasswordVerificationError.generic diff --git a/TelegramCore/SavedStickerItem.swift b/TelegramCore/SavedStickerItem.swift index a51aacb25b..7b58381d05 100644 --- a/TelegramCore/SavedStickerItem.swift +++ b/TelegramCore/SavedStickerItem.swift @@ -25,6 +25,6 @@ public final class SavedStickerItem: OrderedItemListEntryContents, Equatable { } public static func ==(lhs: SavedStickerItem, rhs: SavedStickerItem) -> Bool { - return lhs.file.isEqual(rhs.file) && lhs.stringRepresentations == rhs.stringRepresentations + return lhs.file.isEqual(to: rhs.file) && lhs.stringRepresentations == rhs.stringRepresentations } } diff --git a/TelegramCore/SearchMessages.swift b/TelegramCore/SearchMessages.swift index a2acd540f8..ff1267dd9c 100644 --- a/TelegramCore/SearchMessages.swift +++ b/TelegramCore/SearchMessages.swift @@ -81,10 +81,10 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q } } return account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, filter: filter, minDate: 0, maxDate: Int32.max - 1, offsetId: 0, addOffset: 0, limit: 100, maxId: Int32.max - 1, minId: 0, hash: 0)) - |> map {Optional($0)} - |> `catch` { _ -> Signal in - return .single(nil) - } |> mapError {_ in} + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } } else { return .never() } @@ -97,10 +97,9 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q case .general: remoteSearchResult = account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64), automaticFloodWait: false) |> map(Optional.init) - |> `catch` { _ -> Signal in + |> `catch` { _ -> Signal in return .single(nil) } - |> mapError {_ in} } let processedSearchResult = remoteSearchResult @@ -178,7 +177,8 @@ public func downloadMessage(postbox: Postbox, network: Network, messageId: Messa if let _ = message { return .single(message) } else { - return postbox.loadedPeerWithId(messageId.peerId) |> mapToSignal { peer -> Signal in + return postbox.loadedPeerWithId(messageId.peerId) + |> mapToSignal { peer -> Signal in let signal: Signal if messageId.peerId.namespace == Namespaces.Peer.CloudChannel { if let channel = apiInputChannel(peer) { @@ -190,7 +190,15 @@ public func downloadMessage(postbox: Postbox, network: Network, messageId: Messa signal = network.request(Api.functions.messages.getMessages(id: [Api.InputMessage.inputMessageID(id: messageId.id)])) } - return signal |> mapError {_ in} |> mapToSignal { result -> Signal in + return signal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result = result else { + return .single(nil) + } let messages: [Api.Message] let chats: [Api.Chat] let users: [Api.User] @@ -240,10 +248,9 @@ public func downloadMessage(postbox: Postbox, network: Network, messageId: Messa return postboxSignal } - - } - |> `catch` { _ -> Signal in - return .single(nil) + } + |> `catch` { _ -> Signal in + return .single(nil) } } } @@ -271,7 +278,7 @@ func fetchRemoteMessage(postbox: Postbox, network: Network, message: MessageRefe |> `catch` { _ -> Signal in return .single(nil) } - |> mapToSignal { result -> Signal in + |> mapToSignal { result -> Signal in guard let result = result else { return .single(nil) } @@ -287,7 +294,7 @@ func fetchRemoteMessage(postbox: Postbox, network: Network, message: MessageRefe messages = apiMessages chats = apiChats users = apiUsers - case let.messagesSlice(_, apiMessages, apiChats, apiUsers): + case let .messagesSlice(_, apiMessages, apiChats, apiUsers): messages = apiMessages chats = apiChats users = apiUsers diff --git a/TelegramCore/SearchPeers.swift b/TelegramCore/SearchPeers.swift index c554bb800c..7159b11345 100644 --- a/TelegramCore/SearchPeers.swift +++ b/TelegramCore/SearchPeers.swift @@ -25,84 +25,87 @@ public struct FoundPeer: Equatable { public func searchPeers(account: Account, query: String) -> Signal<([FoundPeer], [FoundPeer]), NoError> { let searchResult = account.network.request(Api.functions.contacts.search(q: query, limit: 20), automaticFloodWait: false) - |> map { Optional($0) } + |> map(Optional.init) |> `catch` { _ in return Signal.single(nil) } let processedSearchResult = searchResult - |> mapToSignal { result -> Signal<([FoundPeer], [FoundPeer]), NoError> in - if let result = result { - switch result { - case let .found(myResults, results, chats, users): - return account.postbox.transaction { transaction -> ([FoundPeer], [FoundPeer]) in - var peers: [PeerId: Peer] = [:] - var subscribers: [PeerId: Int32] = [:] - for user in users { - if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { - peers[user.id] = user - } + |> mapToSignal { result -> Signal<([FoundPeer], [FoundPeer]), NoError> in + if let result = result { + switch result { + case let .found(myResults, results, chats, users): + return account.postbox.transaction { transaction -> ([FoundPeer], [FoundPeer]) in + var peers: [PeerId: Peer] = [:] + var subscribers: [PeerId: Int32] = [:] + for user in users { + if let user = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers[user.id] = user } - - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers[groupOrChannel.id] = groupOrChannel - switch chat { - /*feed*/ - case let .channel(_, _, _, _, _, _, _, _, _, _, _, participantsCount/*, _*/): - if let participantsCount = participantsCount { - subscribers[groupOrChannel.id] = participantsCount - } - default: - break - } - } - } - - updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in - return updated - }) - - var renderedMyPeers: [FoundPeer] = [] - for result in myResults { - let peerId: PeerId - switch result { - case let .peerUser(userId): - peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) - case let .peerChat(chatId): - peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) - case let .peerChannel(channelId): - peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) - } - if let peer = peers[peerId] { - renderedMyPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) - } - } - - var renderedPeers: [FoundPeer] = [] - for result in results { - let peerId: PeerId - switch result { - case let .peerUser(userId): - peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) - case let .peerChat(chatId): - peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) - case let .peerChannel(channelId): - peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) - } - if let peer = peers[peerId] { - renderedPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) - } - } - - - - return (renderedMyPeers, renderedPeers) } + + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers[groupOrChannel.id] = groupOrChannel + switch chat { + /*feed*/ + case let .channel(_, _, _, _, _, _, _, _, _, _, _, participantsCount/*, _*/): + if let participantsCount = participantsCount { + subscribers[groupOrChannel.id] = participantsCount + } + default: + break + } + } + } + + updatePeers(transaction: transaction, peers: Array(peers.values), update: { _, updated in + return updated + }) + + var renderedMyPeers: [FoundPeer] = [] + for result in myResults { + let peerId: PeerId + switch result { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + if let peer = peers[peerId] { + if let group = peer as? TelegramGroup, group.migrationReference != nil { + continue + } + renderedMyPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) + } + } + + var renderedPeers: [FoundPeer] = [] + for result in results { + let peerId: PeerId + switch result { + case let .peerUser(userId): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .peerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .peerChannel(channelId): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + } + if let peer = peers[peerId] { + if let group = peer as? TelegramGroup, group.migrationReference != nil { + continue + } + renderedPeers.append(FoundPeer(peer: peer, subscribers: subscribers[peerId])) + } + } + + return (renderedMyPeers, renderedPeers) } - } else { - return .single(([], [])) } - + } else { + return .single(([], [])) + } } return processedSearchResult diff --git a/TelegramCore/SearchStickers.swift b/TelegramCore/SearchStickers.swift index 88b532b617..eaa795b182 100644 --- a/TelegramCore/SearchStickers.swift +++ b/TelegramCore/SearchStickers.swift @@ -17,7 +17,7 @@ public final class FoundStickerItem: Equatable { } public static func ==(lhs: FoundStickerItem, rhs: FoundStickerItem) -> Bool { - if !lhs.file.isEqual(rhs.file) { + if !lhs.file.isEqual(to: rhs.file) { return false } if lhs.stringRepresentations != rhs.stringRepresentations { @@ -74,20 +74,36 @@ final class CachedStickerQueryResult: PostboxCoding { private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 100, highWaterItemCount: 200) -public func searchStickers(account: Account, query: String) -> Signal<[FoundStickerItem], NoError> { +public struct SearchStickersScope: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let installed = SearchStickersScope(rawValue: 1 << 0) + public static let remote = SearchStickersScope(rawValue: 1 << 1) +} + +public func searchStickers(account: Account, query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<[FoundStickerItem], NoError> { + if scope.isEmpty { + return .single([]) + } return account.postbox.transaction { transaction -> ([FoundStickerItem], CachedStickerQueryResult?) in var result: [FoundStickerItem] = [] - for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, key: ValueBoxKey(query).toMemoryBuffer()) { - if let item = item as? StickerPackItem { - var stringRepresentations: [String] = [] - for key in item.indexKeys { - key.withDataNoCopy { data in - if let string = String(data: data, encoding: .utf8) { - stringRepresentations.append(string) + if scope.contains(.installed) { + for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, key: ValueBoxKey(query).toMemoryBuffer()) { + if let item = item as? StickerPackItem { + var stringRepresentations: [String] = [] + for key in item.indexKeys { + key.withDataNoCopy { data in + if let string = String(data: data, encoding: .utf8) { + stringRepresentations.append(string) + } } } + result.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) } - result.append(FoundStickerItem(file: item.file, stringRepresentations: stringRepresentations)) } } @@ -96,6 +112,9 @@ public func searchStickers(account: Account, query: String) -> Signal<[FoundStic return (result, cached) } |> mapToSignal { localItems, cached -> Signal<[FoundStickerItem], NoError> in var tempResult: [FoundStickerItem] = localItems + if !scope.contains(.remote) { + return .single(tempResult) + } let currentItems = Set(localItems.map { $0.file.fileId }) if let cached = cached { for file in cached.items { @@ -217,10 +236,10 @@ public func searchStickerSets(postbox: Postbox, query: String) -> Signal switchToLatest } -public func searchGifs(account: Account, query: String) -> Signal { +public func searchGifs(account: Account, query: String) -> Signal { return resolvePeerByName(account: account, name: "gif") - |> filter {$0 != nil} - |> map {$0!} + |> filter { $0 != nil } + |> map { $0! } |> mapToSignal { peerId -> Signal in return account.postbox.loadedPeerWithId(peerId) } diff --git a/TelegramCore/SecureIdDriversLicenseValue.swift b/TelegramCore/SecureIdDriversLicenseValue.swift index 3ea51179fb..5d98ed7048 100644 --- a/TelegramCore/SecureIdDriversLicenseValue.swift +++ b/TelegramCore/SecureIdDriversLicenseValue.swift @@ -4,14 +4,16 @@ public struct SecureIdDriversLicenseValue: Equatable { public var identifier: String public var expiryDate: SecureIdDate? public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] public var selfieDocument: SecureIdVerificationDocumentReference? public var frontSideDocument: SecureIdVerificationDocumentReference? public var backSideDocument: SecureIdVerificationDocumentReference? - public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { self.identifier = identifier self.expiryDate = expiryDate self.verificationDocuments = verificationDocuments + self.translations = translations self.selfieDocument = selfieDocument self.frontSideDocument = frontSideDocument self.backSideDocument = backSideDocument @@ -27,6 +29,9 @@ public struct SecureIdDriversLicenseValue: Equatable { if lhs.verificationDocuments != rhs.verificationDocuments { return false } + if lhs.translations != rhs.translations { + return false + } if lhs.selfieDocument != rhs.selfieDocument { return false } @@ -41,7 +46,7 @@ public struct SecureIdDriversLicenseValue: Equatable { } extension SecureIdDriversLicenseValue { - init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { guard let identifier = dict["document_no"] as? String else { return nil } @@ -49,16 +54,16 @@ extension SecureIdDriversLicenseValue { let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences - self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) } - func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { var dict: [String: Any] = [:] dict["document_no"] = self.identifier if let expiryDate = self.expiryDate { dict["expiry_date"] = expiryDate.serialize() } - return (dict, self.verificationDocuments, self.selfieDocument, self.frontSideDocument, self.backSideDocument) + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument, self.backSideDocument) } } diff --git a/TelegramCore/SecureIdForm.swift b/TelegramCore/SecureIdForm.swift index f53feb2ebb..5d7516653b 100644 --- a/TelegramCore/SecureIdForm.swift +++ b/TelegramCore/SecureIdForm.swift @@ -5,12 +5,13 @@ import Foundation import Postbox #endif -public enum SecureIdRequestedFormField: Equatable { +public indirect enum SecureIdRequestedFormField: Equatable { + case oneOf([SecureIdRequestedFormField]) case personalDetails - case passport(selfie: Bool) - case driversLicense(selfie: Bool) - case idCard(selfie: Bool) - case internalPassport(selfie: Bool) + case passport(selfie: Bool, translation: Bool) + case driversLicense(selfie: Bool, translation: Bool) + case idCard(selfie: Bool, translation: Bool) + case internalPassport(selfie: Bool, translation: Bool) case passportRegistration case address case utilityBill diff --git a/TelegramCore/SecureIdIDCardValue.swift b/TelegramCore/SecureIdIDCardValue.swift index 1d97a6a3d1..f2d3d8eeba 100644 --- a/TelegramCore/SecureIdIDCardValue.swift +++ b/TelegramCore/SecureIdIDCardValue.swift @@ -4,14 +4,16 @@ public struct SecureIdIDCardValue: Equatable { public var identifier: String public var expiryDate: SecureIdDate? public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] public var selfieDocument: SecureIdVerificationDocumentReference? public var frontSideDocument: SecureIdVerificationDocumentReference? public var backSideDocument: SecureIdVerificationDocumentReference? - public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { self.identifier = identifier self.expiryDate = expiryDate self.verificationDocuments = verificationDocuments + self.translations = translations self.selfieDocument = selfieDocument self.frontSideDocument = frontSideDocument self.backSideDocument = backSideDocument @@ -27,6 +29,9 @@ public struct SecureIdIDCardValue: Equatable { if lhs.verificationDocuments != rhs.verificationDocuments { return false } + if lhs.translations != rhs.translations { + return false + } if lhs.selfieDocument != rhs.selfieDocument { return false } @@ -41,7 +46,7 @@ public struct SecureIdIDCardValue: Equatable { } extension SecureIdIDCardValue { - init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?, backSideDocument: SecureIdVerificationDocumentReference?) { guard let identifier = dict["document_no"] as? String else { return nil } @@ -49,16 +54,16 @@ extension SecureIdIDCardValue { let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences - self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument, backSideDocument: backSideDocument) } - func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { var dict: [String: Any] = [:] dict["document_no"] = self.identifier if let expiryDate = self.expiryDate { dict["expiry_date"] = expiryDate.serialize() } - return (dict, self.verificationDocuments, self.selfieDocument, self.frontSideDocument, self.backSideDocument) + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument, self.backSideDocument) } } diff --git a/TelegramCore/SecureIdInternalPassportValue.swift b/TelegramCore/SecureIdInternalPassportValue.swift index 0cc5990268..fa0cb61ae7 100644 --- a/TelegramCore/SecureIdInternalPassportValue.swift +++ b/TelegramCore/SecureIdInternalPassportValue.swift @@ -4,13 +4,15 @@ public struct SecureIdInternalPassportValue: Equatable { public var identifier: String public var expiryDate: SecureIdDate? public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] public var selfieDocument: SecureIdVerificationDocumentReference? public var frontSideDocument: SecureIdVerificationDocumentReference? - public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { self.identifier = identifier self.expiryDate = expiryDate self.verificationDocuments = verificationDocuments + self.translations = translations self.selfieDocument = selfieDocument self.frontSideDocument = frontSideDocument } @@ -25,6 +27,9 @@ public struct SecureIdInternalPassportValue: Equatable { if lhs.verificationDocuments != rhs.verificationDocuments { return false } + if lhs.translations != rhs.translations { + return false + } if lhs.selfieDocument != rhs.selfieDocument { return false } @@ -36,7 +41,7 @@ public struct SecureIdInternalPassportValue: Equatable { } extension SecureIdInternalPassportValue { - init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { guard let identifier = dict["document_no"] as? String else { return nil } @@ -44,16 +49,16 @@ extension SecureIdInternalPassportValue { let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences - self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) } - func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { var dict: [String: Any] = [:] dict["document_no"] = self.identifier if let expiryDate = self.expiryDate { dict["expiry_date"] = expiryDate.serialize() } - return (dict, self.verificationDocuments, self.selfieDocument, self.frontSideDocument) + return (dict, self.verificationDocuments, self.translations, self.selfieDocument, self.frontSideDocument) } } diff --git a/TelegramCore/SecureIdPassportValue.swift b/TelegramCore/SecureIdPassportValue.swift index d068636adc..4c8af48014 100644 --- a/TelegramCore/SecureIdPassportValue.swift +++ b/TelegramCore/SecureIdPassportValue.swift @@ -4,13 +4,15 @@ public struct SecureIdPassportValue: Equatable { public var identifier: String public var expiryDate: SecureIdDate? public var verificationDocuments: [SecureIdVerificationDocumentReference] + public var translations: [SecureIdVerificationDocumentReference] public var selfieDocument: SecureIdVerificationDocumentReference? public var frontSideDocument: SecureIdVerificationDocumentReference? - public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + public init(identifier: String, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { self.identifier = identifier self.expiryDate = expiryDate self.verificationDocuments = verificationDocuments + self.translations = translations self.selfieDocument = selfieDocument self.frontSideDocument = frontSideDocument } @@ -25,6 +27,9 @@ public struct SecureIdPassportValue: Equatable { if lhs.verificationDocuments != rhs.verificationDocuments { return false } + if lhs.translations != rhs.translations { + return false + } if lhs.selfieDocument != rhs.selfieDocument { return false } @@ -36,7 +41,7 @@ public struct SecureIdPassportValue: Equatable { } extension SecureIdPassportValue { - init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { + init?(dict: [String: Any], fileReferences: [SecureIdVerificationDocumentReference], translations: [SecureIdVerificationDocumentReference], selfieDocument: SecureIdVerificationDocumentReference?, frontSideDocument: SecureIdVerificationDocumentReference?) { guard let identifier = dict["document_no"] as? String else { return nil } @@ -44,16 +49,17 @@ extension SecureIdPassportValue { let verificationDocuments: [SecureIdVerificationDocumentReference] = fileReferences - self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) + self.init(identifier: identifier, expiryDate: expiryDate, verificationDocuments: verificationDocuments, translations: translations, selfieDocument: selfieDocument, frontSideDocument: frontSideDocument) } - func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { + func serialize() -> ([String: Any], [SecureIdVerificationDocumentReference], [SecureIdVerificationDocumentReference], SecureIdVerificationDocumentReference?, SecureIdVerificationDocumentReference?) { var dict: [String: Any] = [:] dict["document_no"] = self.identifier if let expiryDate = self.expiryDate { dict["expiry_date"] = expiryDate.serialize() } - return (dict, self.verificationDocuments, self.selfieDocument, self.frontSideDocument) + return (dict, self.verificationDocuments, + self.translations, self.selfieDocument, self.frontSideDocument) } } diff --git a/TelegramCore/SecureIdValue.swift b/TelegramCore/SecureIdValue.swift index 95934dacb4..07e4d165d8 100644 --- a/TelegramCore/SecureIdValue.swift +++ b/TelegramCore/SecureIdValue.swift @@ -136,16 +136,18 @@ public struct SecureIdValueWithContext: Equatable { public let value: SecureIdValue public let errors: [SecureIdValueContentErrorKey: SecureIdValueContentError] let files: [SecureIdEncryptedValueFileMetadata] + let translations: [SecureIdEncryptedValueFileMetadata] let selfie: SecureIdEncryptedValueFileMetadata? let frontSide: SecureIdEncryptedValueFileMetadata? let backSide: SecureIdEncryptedValueFileMetadata? let encryptedMetadata: SecureIdEncryptedValueMetadata? let opaqueHash: Data - init(value: SecureIdValue, errors: [SecureIdValueContentErrorKey: SecureIdValueContentError], files: [SecureIdEncryptedValueFileMetadata], selfie: SecureIdEncryptedValueFileMetadata?, frontSide: SecureIdEncryptedValueFileMetadata?, backSide: SecureIdEncryptedValueFileMetadata?, encryptedMetadata: SecureIdEncryptedValueMetadata?, opaqueHash: Data) { + init(value: SecureIdValue, errors: [SecureIdValueContentErrorKey: SecureIdValueContentError], files: [SecureIdEncryptedValueFileMetadata], translations: [SecureIdEncryptedValueFileMetadata], selfie: SecureIdEncryptedValueFileMetadata?, frontSide: SecureIdEncryptedValueFileMetadata?, backSide: SecureIdEncryptedValueFileMetadata?, encryptedMetadata: SecureIdEncryptedValueMetadata?, opaqueHash: Data) { self.value = value self.errors = errors self.files = files + self.translations = translations self.selfie = selfie self.frontSide = frontSide self.backSide = backSide @@ -158,6 +160,6 @@ public struct SecureIdValueWithContext: Equatable { for key in keys { errors.removeValue(forKey: key) } - return SecureIdValueWithContext(value: self.value, errors: errors, files: self.files, selfie: self.selfie, frontSide: self.frontSide, backSide: self.backSide, encryptedMetadata: self.encryptedMetadata, opaqueHash: self.opaqueHash) + return SecureIdValueWithContext(value: self.value, errors: errors, files: self.files, translations: self.translations, selfie: self.selfie, frontSide: self.frontSide, backSide: self.backSide, encryptedMetadata: self.encryptedMetadata, opaqueHash: self.opaqueHash) } } diff --git a/TelegramCore/SecureIdValueContentError.swift b/TelegramCore/SecureIdValueContentError.swift index 610254d267..42b7269d09 100644 --- a/TelegramCore/SecureIdValueContentError.swift +++ b/TelegramCore/SecureIdValueContentError.swift @@ -1,9 +1,12 @@ import Foundation public enum SecureIdValueContentErrorKey: Hashable { + case value(SecureIdValueKey) case field(SecureIdValueContentErrorField) case file(hash: Data) case files(hashes: Set) + case translationFile(hash: Data) + case translationFiles(hashes: Set) case selfie(hash: Data) case frontSide(hash: Data) case backSide(hash: Data) @@ -62,6 +65,8 @@ func parseSecureIdValueContentErrors(dataHash: Data?, fileHashes: Set, sel var result: [SecureIdValueContentErrorKey: SecureIdValueContentError] = [:] for error in errors { switch error { + case let .secureValueError(type, _, text): + result[.value(SecureIdValueKey(apiType: type))] = text case let .secureValueErrorData(type, errorDataHash, field, text): if errorDataHash.makeData() == dataHash { switch type { @@ -108,6 +113,21 @@ func parseSecureIdValueContentErrors(dataHash: Data?, fileHashes: Set, sel if containsAll { result[.files(hashes: Set(fileHash.map { $0.makeData() }))] = text } + case let .secureValueErrorTranslationFile(_, fileHash, text): + if fileHashes.contains(fileHash.makeData()) { + result[.translationFile(hash: fileHash.makeData())] = text + } + case let .secureValueErrorTranslationFiles(_, fileHash, text): + var containsAll = true + loop: for hash in fileHash { + if !fileHashes.contains(hash.makeData()) { + containsAll = false + break loop + } + } + if containsAll { + result[.translationFiles(hashes: Set(fileHash.map { $0.makeData() }))] = text + } case let .secureValueErrorSelfie(_, fileHash, text): if selfieHash == fileHash.makeData() { result[.selfie(hash: fileHash.makeData())] = text diff --git a/TelegramCore/Serialization.swift b/TelegramCore/Serialization.swift index 2f1eeeab38..32c39556ca 100644 --- a/TelegramCore/Serialization.swift +++ b/TelegramCore/Serialization.swift @@ -202,7 +202,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 84 + return 86 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/TelegramCore/StandaloneSendMessage.swift b/TelegramCore/StandaloneSendMessage.swift index 6080cb94a7..8ba4bc326f 100644 --- a/TelegramCore/StandaloneSendMessage.swift +++ b/TelegramCore/StandaloneSendMessage.swift @@ -113,27 +113,28 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M switch content { case let .text(text): sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities)) - |> mapError { _ -> NoError in - return NoError() + |> `catch` { _ -> Signal in + return .complete() } case let .media(inputMedia, text): sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyToMsgId: replyMessageId, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities)) - |> mapError { _ -> NoError in - return NoError() + |> `catch` { _ -> Signal in + return .complete() } } return sendMessageRequest - |> mapToSignal { result -> Signal in - return .complete() - } - |> `catch` { _ -> Signal in - return .complete() - } + |> mapToSignal { result -> Signal in + return .complete() + } + |> `catch` { _ -> Signal in + return .complete() + } } else { return .complete() } - } |> switchToLatest + } + |> switchToLatest } private enum UploadMediaEvent { diff --git a/TelegramCore/StickerSetInstallation.swift b/TelegramCore/StickerSetInstallation.swift index f8b24fdeee..9b7e4e86cf 100644 --- a/TelegramCore/StickerSetInstallation.swift +++ b/TelegramCore/StickerSetInstallation.swift @@ -40,7 +40,7 @@ public func requestStickerSet(postbox: Postbox, network: Network, reference: Sti input = .inputStickerSetID(id: id, accessHash: accessHash) } - let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, Void> = { collectionId in + let localSignal: (ItemCollectionId) -> Signal<(ItemCollectionInfo, [ItemCollectionItem])?, NoError> = { collectionId in return postbox.transaction { transaction -> (ItemCollectionInfo, [ItemCollectionItem])? in return transaction.getItemCollectionInfoItems(namespace: Namespaces.ItemCollection.CloudStickerPacks, id: collectionId) } @@ -196,13 +196,13 @@ public func installStickerSetInteractively(account:Account, info: StickerPackCol } -public func uninstallStickerSetInteractively(account:Account, info:StickerPackCollectionInfo) -> Signal { +public func uninstallStickerSetInteractively(account:Account, info:StickerPackCollectionInfo) -> Signal { return account.network.request(Api.functions.messages.uninstallStickerSet(stickerset: .inputStickerSetID(id: info.id.id, accessHash: info.accessHash))) - |> mapError {_ in - - } - |> mapToSignal { result-> Signal in - switch result { + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> mapToSignal { result -> Signal in + switch result { case .boolTrue: return account.postbox.transaction { transaction -> Void in var collections = transaction.getCollectionsItems(namespace: info.id.namespace) @@ -218,7 +218,7 @@ public func uninstallStickerSetInteractively(account:Account, info:StickerPackCo } case .boolFalse: return .complete() - } + } } } diff --git a/TelegramCore/SupportPeerId.swift b/TelegramCore/SupportPeerId.swift index 3ed5be9b8e..a3bba70ead 100644 --- a/TelegramCore/SupportPeerId.swift +++ b/TelegramCore/SupportPeerId.swift @@ -9,15 +9,15 @@ #endif -public func supportPeerId(account:Account) -> Signal { +public func supportPeerId(account:Account) -> Signal { return account.network.request(Api.functions.help.getSupport()) - |> map { Optional($0) } - |> `catch` { _ in - return Signal.single(nil) - } - |> mapToSignal { support -> Signal in - if let support = support { - switch support { + |> map(Optional.init) + |> `catch` { _ in + return Signal.single(nil) + } + |> mapToSignal { support -> Signal in + if let support = support { + switch support { case let .support(phoneNumber: _, user: user): let user = TelegramUser(user: user) return account.postbox.transaction { transaction -> PeerId in @@ -26,8 +26,8 @@ public func supportPeerId(account:Account) -> Signal { }) return user.id } - } } - return .single(nil) + } + return .single(nil) } } diff --git a/TelegramCore/SynchronizeSavedStickersOperation.swift b/TelegramCore/SynchronizeSavedStickersOperation.swift index e9ee9642e8..b6386038bc 100644 --- a/TelegramCore/SynchronizeSavedStickersOperation.swift +++ b/TelegramCore/SynchronizeSavedStickersOperation.swift @@ -184,7 +184,7 @@ public func removeSavedSticker(transaction: Transaction, mediaId: MediaId) { } } -public func removeSavedSticker(postbox: Postbox, mediaId: MediaId) -> Signal { +public func removeSavedSticker(postbox: Postbox, mediaId: MediaId) -> Signal { return postbox.transaction { transaction in if let entry = transaction.getOrderedItemListItem(collectionId: Namespaces.OrderedItemList.CloudSavedStickers, itemId: RecentMediaItemId(mediaId).rawValue), let item = entry.contents as? SavedStickerItem { if let resource = item.file.resource as? CloudDocumentMediaResource { diff --git a/TelegramCore/TelegramMediaAction.swift b/TelegramCore/TelegramMediaAction.swift index f8d133cb89..d7e31ce19f 100644 --- a/TelegramCore/TelegramMediaAction.swift +++ b/TelegramCore/TelegramMediaAction.swift @@ -335,12 +335,16 @@ public final class TelegramMediaAction: Media { self.action.encode(encoder) } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaAction { return self.action == other.action } return false } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMediaAction? { diff --git a/TelegramCore/TelegramMediaContact.swift b/TelegramCore/TelegramMediaContact.swift index fccb12edad..b444f5e238 100644 --- a/TelegramCore/TelegramMediaContact.swift +++ b/TelegramCore/TelegramMediaContact.swift @@ -56,7 +56,7 @@ public final class TelegramMediaContact: Media { } } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaContact { if self.id == other.id && self.firstName == other.firstName && self.lastName == other.lastName && self.phoneNumber == other.phoneNumber && self.peerId == other.peerId && self.vCardData == other.vCardData && self.peerIds == other.peerIds { return true @@ -64,4 +64,8 @@ public final class TelegramMediaContact: Media { } return false } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } diff --git a/TelegramCore/TelegramMediaExpiredContent.swift b/TelegramCore/TelegramMediaExpiredContent.swift index fda5e6ecc0..dc90b36be9 100644 --- a/TelegramCore/TelegramMediaExpiredContent.swift +++ b/TelegramCore/TelegramMediaExpiredContent.swift @@ -28,11 +28,15 @@ public final class TelegramMediaExpiredContent: Media { encoder.encodeInt32(self.data.rawValue, forKey: "d") } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaExpiredContent { return self.data == other.data } else { return false } } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } diff --git a/TelegramCore/TelegramMediaFile.swift b/TelegramCore/TelegramMediaFile.swift index 5c891c5940..29c850fcbd 100644 --- a/TelegramCore/TelegramMediaFile.swift +++ b/TelegramCore/TelegramMediaFile.swift @@ -376,7 +376,7 @@ public final class TelegramMediaFile: Media, Equatable { return durationForFileAttributes(self.attributes) } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { guard let other = other as? TelegramMediaFile else { return false } @@ -405,9 +405,43 @@ public final class TelegramMediaFile: Media, Equatable { return false } - /*if self.attributes != other.attributes { + return true + } + + public func isSemanticallyEqual(to other: Media) -> Bool { + guard let other = other as? TelegramMediaFile else { return false - }*/ + } + + if self.fileId != other.fileId { + return false + } + + if self.partialReference != other.partialReference { + return false + } + + if !self.resource.id.isEqual(to: other.resource.id) { + return false + } + + if self.previewRepresentations.count != other.previewRepresentations.count { + return false + } + + for i in 0 ..< self.previewRepresentations.count { + if !self.previewRepresentations[i].isSemanticallyEqual(to: other.previewRepresentations[i]) { + return false + } + } + + if self.size != other.size { + return false + } + + if self.mimeType != other.mimeType { + return false + } return true } @@ -430,7 +464,7 @@ public final class TelegramMediaFile: Media, Equatable { } public func ==(lhs: TelegramMediaFile, rhs: TelegramMediaFile) -> Bool { - return lhs.isEqual(rhs) + return lhs.isEqual(to: rhs) } extension StickerPackReference { diff --git a/TelegramCore/TelegramMediaGame.swift b/TelegramCore/TelegramMediaGame.swift index 03beb97a09..3ccabcacd0 100644 --- a/TelegramCore/TelegramMediaGame.swift +++ b/TelegramCore/TelegramMediaGame.swift @@ -57,7 +57,7 @@ public final class TelegramMediaGame: Media { } } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { guard let other = other as? TelegramMediaGame else { return false } @@ -83,7 +83,7 @@ public final class TelegramMediaGame: Media { } if let lhsImage = self.image, let rhsImage = other.image { - if !lhsImage.isEqual(rhsImage) { + if !lhsImage.isEqual(to: rhsImage) { return false } } else if (self.image != nil) != (other.image != nil) { @@ -91,7 +91,7 @@ public final class TelegramMediaGame: Media { } if let lhsFile = self.file, let rhsFile = other.file { - if !lhsFile.isEqual(rhsFile) { + if !lhsFile.isEqual(to: rhsFile) { return false } } else if (self.file != nil) != (other.file != nil) { @@ -100,6 +100,10 @@ public final class TelegramMediaGame: Media { return true } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } extension TelegramMediaGame { diff --git a/TelegramCore/TelegramMediaImage.swift b/TelegramCore/TelegramMediaImage.swift index 9e3062dd8c..80eea838d4 100644 --- a/TelegramCore/TelegramMediaImage.swift +++ b/TelegramCore/TelegramMediaImage.swift @@ -113,7 +113,7 @@ public final class TelegramMediaImage: Media, Equatable { } } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaImage { if other.imageId != self.imageId { return false @@ -129,8 +129,30 @@ public final class TelegramMediaImage: Media, Equatable { return false } + public func isSemanticallyEqual(to other: Media) -> Bool { + if let other = other as? TelegramMediaImage { + if other.imageId != self.imageId { + return false + } + if other.representations.count != self.representations.count { + return false + } + for i in 0 ..< self.representations.count { + if !self.representations[i].isSemanticallyEqual(to: other.representations[i]) { + return false + } + } + + if self.partialReference != other.partialReference { + return false + } + return true + } + return false + } + public static func ==(lhs: TelegramMediaImage, rhs: TelegramMediaImage) -> Bool { - return lhs.isEqual(rhs) + return lhs.isEqual(to: rhs) } public func withUpdatedPartialReference(_ partialReference: PartialMediaReference?) -> TelegramMediaImage { @@ -161,6 +183,16 @@ public final class TelegramMediaImageRepresentation: PostboxCoding, Equatable, C public var description: String { return "(\(Int(dimensions.width))x\(Int(dimensions.height)))" } + + public func isSemanticallyEqual(to other: TelegramMediaImageRepresentation) -> Bool { + if self.dimensions != other.dimensions { + return false + } + if !self.resource.id.isEqual(to: other.resource.id) { + return false + } + return true + } } public func ==(lhs: TelegramMediaImageRepresentation, rhs: TelegramMediaImageRepresentation) -> Bool { diff --git a/TelegramCore/TelegramMediaInvoice.swift b/TelegramCore/TelegramMediaInvoice.swift index ec4c078265..97acdb90e5 100644 --- a/TelegramCore/TelegramMediaInvoice.swift +++ b/TelegramCore/TelegramMediaInvoice.swift @@ -20,9 +20,6 @@ public struct TelegramMediaInvoiceFlags: OptionSet { public static let shippingAddressRequested = TelegramMediaInvoiceFlags(rawValue: 1 << 1) } -//flags: Int32, title: String, description: String, photo: Api.WebDocument?, receiptMsgId: Int32?, currency: String, totalAmount: Int64, startParam: String -//messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia; - public final class TelegramMediaInvoice: Media { public var peerIds: [PeerId] = [] @@ -89,7 +86,7 @@ public final class TelegramMediaInvoice: Media { } } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { guard let other = other as? TelegramMediaInvoice else { return false } @@ -125,4 +122,7 @@ public final class TelegramMediaInvoice: Media { return true } + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } diff --git a/TelegramCore/TelegramMediaMap.swift b/TelegramCore/TelegramMediaMap.swift index 9faacd3ee4..de78e0a4ae 100644 --- a/TelegramCore/TelegramMediaMap.swift +++ b/TelegramCore/TelegramMediaMap.swift @@ -181,7 +181,7 @@ public final class TelegramMediaMap: Media { } } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaMap { if self.latitude != other.latitude || self.longitude != other.longitude { return false @@ -199,6 +199,10 @@ public final class TelegramMediaMap: Media { } return false } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } func telegramMediaMapFromApiGeoPoint(_ geo: Api.GeoPoint, title: String?, address: String?, provider: String?, venueId: String?, venueType: String?, liveBroadcastingTimeout: Int32?) -> TelegramMediaMap { diff --git a/TelegramCore/TelegramMediaWebDocument.swift b/TelegramCore/TelegramMediaWebDocument.swift index 258d9ac1ce..1ca7534536 100644 --- a/TelegramCore/TelegramMediaWebDocument.swift +++ b/TelegramCore/TelegramMediaWebDocument.swift @@ -37,7 +37,7 @@ public class TelegramMediaWebFile: Media { encoder.encodeObjectArray(self.attributes, forKey: "at") } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { guard let other = other as? TelegramMediaWebFile else { return false } @@ -56,6 +56,10 @@ public class TelegramMediaWebFile: Media { return true } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } public var dimensions: CGSize? { return dimensionsForFileAttributes(self.attributes) diff --git a/TelegramCore/TelegramMediaWebpage.swift b/TelegramCore/TelegramMediaWebpage.swift index b1f4b51cae..0f8645be28 100644 --- a/TelegramCore/TelegramMediaWebpage.swift +++ b/TelegramCore/TelegramMediaWebpage.swift @@ -168,7 +168,7 @@ public func ==(lhs: TelegramMediaWebpageLoadedContent, rhs: TelegramMediaWebpage } if let lhsImage = lhs.image, let rhsImage = rhs.image { - if !lhsImage.isEqual(rhsImage) { + if !lhsImage.isEqual(to: rhsImage) { return false } } else if (lhs.image == nil) != (rhs.image == nil) { @@ -176,7 +176,7 @@ public func ==(lhs: TelegramMediaWebpageLoadedContent, rhs: TelegramMediaWebpage } if let lhsFile = lhs.file, let rhsFile = rhs.file { - if !lhsFile.isEqual(rhsFile) { + if !lhsFile.isEqual(to: rhsFile) { return false } } else if (lhs.file == nil) != (rhs.file == nil) { @@ -243,13 +243,17 @@ public final class TelegramMediaWebpage: Media, Equatable { return true } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if let other = other as? TelegramMediaWebpage, self.webpageId == other.webpageId { return self == other } return false } + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } + public static func ==(lhs: TelegramMediaWebpage, rhs: TelegramMediaWebpage) -> Bool { if lhs.webpageId != rhs.webpageId { return false diff --git a/TelegramCore/TeleramMediaUnsupported.swift b/TelegramCore/TeleramMediaUnsupported.swift index 81f7900092..5ff9e8b0f0 100644 --- a/TelegramCore/TeleramMediaUnsupported.swift +++ b/TelegramCore/TeleramMediaUnsupported.swift @@ -18,10 +18,14 @@ public final class TelegramMediaUnsupported: Media { public func encode(_ encoder: PostboxEncoder) { } - public func isEqual(_ other: Media) -> Bool { + public func isEqual(to other: Media) -> Bool { if other is TelegramMediaUnsupported { return true } return false } + + public func isSemanticallyEqual(to other: Media) -> Bool { + return self.isEqual(to: other) + } } diff --git a/TelegramCore/TermsOfService.swift b/TelegramCore/TermsOfService.swift index 82df723954..cb214afb6e 100644 --- a/TelegramCore/TermsOfService.swift +++ b/TelegramCore/TermsOfService.swift @@ -48,10 +48,10 @@ public func acceptTermsOfService(account: Account, id: String) -> Signal Signal { +public func resetAccountDueTermsOfService(network: Network) -> Signal { return network.request(Api.functions.account.deleteAccount(reason: "Decline ToS update")) - |> retryRequest - |> map {_ in return} + |> retryRequest + |> map { _ in return } } func managedTermsOfServiceUpdates(postbox: Postbox, network: Network, stateManager: AccountStateManager) -> Signal { diff --git a/TelegramCore/ToggleChannelSignatures.swift b/TelegramCore/ToggleChannelSignatures.swift index d32e35e9d1..0452b2528a 100644 --- a/TelegramCore/ToggleChannelSignatures.swift +++ b/TelegramCore/ToggleChannelSignatures.swift @@ -9,8 +9,8 @@ import Foundation import MtProtoKitDynamic #endif -public func toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal { - return account.postbox.transaction { transaction -> Signal in +public func toggleShouldChannelMessagesSignatures(account:Account, peerId:PeerId, enabled: Bool) -> Signal { + return account.postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId) as? TelegramChannel, let inputChannel = apiInputChannel(peer) { return account.network.request(Api.functions.channels.toggleSignatures(channel: inputChannel, enabled: enabled ? .boolTrue : .boolFalse)) |> retryRequest |> map { updates -> Void in account.stateManager.addUpdates(updates) diff --git a/TelegramCore/TwoStepVerification.swift b/TelegramCore/TwoStepVerification.swift index 3932bc6bbb..680af37f59 100644 --- a/TelegramCore/TwoStepVerification.swift +++ b/TelegramCore/TwoStepVerification.swift @@ -52,15 +52,15 @@ public func requestTwoStepVerifiationSettings(network: Network, password: String } } |> mapToSignal { authData -> Signal in - guard let currentPasswordDerivation = authData.currentPasswordDerivation else { + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { return .fail(.generic) } - guard let currentPasswordHash = passwordKDF(password: password, derivation: currentPasswordDerivation) else { + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { return .fail(.generic) } - return network.request(Api.functions.account.getPasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false) + return network.request(Api.functions.account.getPasswordSettings(password: .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1))), automaticFloodWait: false) |> mapError { _ -> AuthorizationPasswordVerificationError in return .generic } @@ -117,15 +117,15 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: } } |> mapToSignal { authData, secureSecret -> Signal in - let currentPasswordHash: Buffer - if let currentPasswordDerivation = authData.currentPasswordDerivation { - if let passwordHash = passwordKDF(password: currentPassword ?? "", derivation: currentPasswordDerivation) { - currentPasswordHash = Buffer(data: passwordHash) + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + if let kdfResult = passwordKDF(password: currentPassword ?? "", derivation: currentPasswordDerivation, srpSessionData: srpSessionData) { + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) } else { return .fail(.generic) } } else { - currentPasswordHash = Buffer(data: Data()) + checkPassword = .inputCheckPasswordEmpty } switch updatedPassword { @@ -135,7 +135,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: flags |= (1 << 0) } - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: .passwordInputSettings(flags: flags, newAlgo: .passwordKdfAlgoUnknown, newPasswordHash: Buffer(data: Data()), hint: "", email: "", newSecureSettings: nil)), automaticFloodWait: true) + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: .passwordInputSettings(flags: flags, newAlgo: .passwordKdfAlgoUnknown, newPasswordHash: Buffer(data: Data()), hint: "", email: "", newSecureSettings: nil)), automaticFloodWait: true) |> mapError { _ -> UpdateTwoStepVerificationPasswordError in return .generic } @@ -171,7 +171,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: updatedSecureSettings = .secureSecretSettings(secureAlgo: updatedSecureSecret.derivation.apiAlgo, secureSecret: Buffer(data: updatedSecureSecret.data), secureSecretId: updatedSecureSecret.id) } - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: updatedPasswordDerivation.apiAlgo, newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSettings: updatedSecureSettings)), automaticFloodWait: false) + return network.request(Api.functions.account.updatePasswordSettings(password: .inputCheckPasswordEmpty, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: updatedPasswordDerivation.apiAlgo, newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSettings: updatedSecureSettings)), automaticFloodWait: false) |> map { _ -> UpdateTwoStepVerificationPasswordResult in return .password(password: password, pendingEmailPattern: nil) } @@ -210,20 +210,22 @@ func updateTwoStepVerificationSecureSecret(network: Network, password: String, s return .generic } |> mapToSignal { authData -> Signal in - guard let currentPasswordDerivation = authData.currentPasswordDerivation else { + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { return .fail(.generic) } - guard let currentPasswordHash = passwordKDF(password: password, derivation: currentPasswordDerivation) else { + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { return .fail(.generic) } + let checkPassword: Api.InputCheckPasswordSRP = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + guard let (encryptedSecret, secretDerivation, secretId) = encryptedSecureSecret(secretData: secret, password: password, inputDerivation: authData.nextSecurePasswordDerivation) else { return .fail(.generic) } let flags: Int32 = (1 << 2) - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash), newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: "", email: "", newSecureSettings: .secureSecretSettings(secureAlgo: secretDerivation.apiAlgo, secureSecret: Buffer(data: encryptedSecret), secureSecretId: secretId))), automaticFloodWait: true) + return network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: .passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: "", email: "", newSecureSettings: .secureSecretSettings(secureAlgo: secretDerivation.apiAlgo, secureSecret: Buffer(data: encryptedSecret), secureSecretId: secretId))), automaticFloodWait: true) |> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in return .generic } @@ -239,18 +241,18 @@ public func updateTwoStepVerificationEmail(account: Account, currentPassword: St return .generic } |> mapToSignal { authData -> Signal in - let currentPasswordHash: Buffer - if let currentPasswordDerivation = authData.currentPasswordDerivation { - guard let passwordHash = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation) else { + let checkPassword: Api.InputCheckPasswordSRP + if let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData { + guard let kdfResult = passwordKDF(password: currentPassword, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { return .fail(.generic) } - currentPasswordHash = Buffer(data: passwordHash) + checkPassword = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) } else { - currentPasswordHash = Buffer(data: Data()) + checkPassword = .inputCheckPasswordEmpty } let flags: Int32 = 1 << 1 - return account.network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: updatedEmail, newSecureSettings: nil)), automaticFloodWait: false) + return account.network.request(Api.functions.account.updatePasswordSettings(password: checkPassword, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newAlgo: nil, newPasswordHash: nil, hint: nil, email: updatedEmail, newSecureSettings: nil)), automaticFloodWait: false) |> map { _ -> UpdateTwoStepVerificationPasswordResult in return .password(password: currentPassword, pendingEmailPattern: nil) } @@ -367,14 +369,16 @@ public func cacheTwoStepPasswordToken(postbox: Postbox, token: TemporaryTwoStepP public func requestTemporaryTwoStepPasswordToken(account: Account, password: String, period: Int32, requiresBiometrics: Bool) -> Signal { return twoStepAuthData(account.network) |> mapToSignal { authData -> Signal in - guard let currentPasswordDerivation = authData.currentPasswordDerivation else { + guard let currentPasswordDerivation = authData.currentPasswordDerivation, let srpSessionData = authData.srpSessionData else { return .fail(MTRpcError(errorCode: 400, errorDescription: "NO_PASSWORD")) } - guard let currentPasswordHash = passwordKDF(password: password, derivation: currentPasswordDerivation) else { + guard let kdfResult = passwordKDF(password: password, derivation: currentPasswordDerivation, srpSessionData: srpSessionData) else { return .fail(MTRpcError(errorCode: 400, errorDescription: "KDF_ERROR")) } - return account.network.request(Api.functions.account.getTmpPassword(passwordHash: Buffer(data: currentPasswordHash), period: period), automaticFloodWait: false) + let checkPassword: Api.InputCheckPasswordSRP = .inputCheckPasswordSRP(srpId: kdfResult.id, A: Buffer(data: kdfResult.A), M1: Buffer(data: kdfResult.M1)) + + return account.network.request(Api.functions.account.getTmpPassword(password: checkPassword, period: period), automaticFloodWait: false) |> map { result -> TemporaryTwoStepPasswordToken in switch result { case let .tmpPassword(tmpPassword, validUntil): diff --git a/TelegramCore/UpdateGroupSpecificStickerset.swift b/TelegramCore/UpdateGroupSpecificStickerset.swift index 21577620ac..4ed49e5737 100644 --- a/TelegramCore/UpdateGroupSpecificStickerset.swift +++ b/TelegramCore/UpdateGroupSpecificStickerset.swift @@ -8,8 +8,14 @@ import Foundation #endif -public func updateGroupSpecificStickerset(postbox: Postbox, network: Network, peerId: PeerId, info: StickerPackCollectionInfo?) -> Signal { - return postbox.loadedPeerWithId(peerId) |> mapToSignal { peer in +public enum UpdateGroupSpecificStickersetError { + case generic +} + +public func updateGroupSpecificStickerset(postbox: Postbox, network: Network, peerId: PeerId, info: StickerPackCollectionInfo?) -> Signal { + return postbox.loadedPeerWithId(peerId) + |> introduceError(UpdateGroupSpecificStickersetError.self) + |> mapToSignal { peer -> Signal in let inputStickerset: Api.InputStickerSet if let info = info { inputStickerset = Api.InputStickerSet.inputStickerSetShortName(shortName: info.shortName) @@ -17,17 +23,21 @@ public func updateGroupSpecificStickerset(postbox: Postbox, network: Network, pe inputStickerset = Api.InputStickerSet.inputStickerSetEmpty } if let inputChannel = apiInputChannel(peer) { - let api = Api.functions.channels.setStickers(channel: inputChannel, stickerset: inputStickerset) - return network.request(api) |> mapError {_ in return} |> mapToSignal { value in + return network.request(Api.functions.channels.setStickers(channel: inputChannel, stickerset: inputStickerset)) + |> mapError { _ -> UpdateGroupSpecificStickersetError in + return .generic + } + |> mapToSignal { value -> Signal in switch value { - case .boolTrue: - return postbox.transaction { transaction -> Void in - return transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current -> CachedPeerData? in - return (current as? CachedChannelData)?.withUpdatedStickerPack(info) - }) - } - default: - return .complete() + case .boolTrue: + return postbox.transaction { transaction -> Void in + return transaction.updatePeerCachedData(peerIds: [peerId], update: { _, current -> CachedPeerData? in + return (current as? CachedChannelData)?.withUpdatedStickerPack(info) + }) + } + |> introduceError(UpdateGroupSpecificStickersetError.self) + default: + return .complete() } } } diff --git a/TelegramCore/UpdateSecretChat.swift b/TelegramCore/UpdateSecretChat.swift index f1b2085bfa..1df89c2d31 100644 --- a/TelegramCore/UpdateSecretChat.swift +++ b/TelegramCore/UpdateSecretChat.swift @@ -43,7 +43,11 @@ func updateSecretChat(accountPeerId: PeerId, transaction: Transaction, chat: Api memcpy(&keyFingerprint, bytes.advanced(by: keyHash.count - 8), 8) } - var updatedState = currentState.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])).withUpdatedEmbeddedState(.basicLayer).withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) + var updatedState = currentState + updatedState = updatedState.withUpdatedKeychain(SecretChatKeychain(keys: [SecretChatKey(fingerprint: keyFingerprint, key: MemoryBuffer(data: key), validity: .indefinite, useCount: 0)])) + updatedState = updatedState.withUpdatedEmbeddedState(.sequenceBasedLayer(SecretChatSequenceBasedLayerState(layerNegotiationState: SecretChatLayerNegotiationState(activeLayer: .layer46, locallyRequestedLayer: nil, remotelyRequestedLayer: nil), rekeyState: nil, baseIncomingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretIncomingDecrypted), baseOutgoingOperationIndex: transaction.operationLogGetNextEntryLocalIndex(peerId: currentPeer.id, tag: OperationLogTags.SecretOutgoing), topProcessedCanonicalIncomingOperationIndex: nil))) + + updatedState = updatedState.withUpdatedKeyFingerprint(SecretChatKeyFingerprint(sha1: SecretChatKeySha1Fingerprint(digest: sha1Digest(key)), sha256: SecretChatKeySha256Fingerprint(digest: sha256Digest(key)))) updatedState = secretChatAddReportCurrentLayerSupportOperationAndUpdateRequestedLayer(transaction: transaction, peerId: currentPeer.id, state: updatedState) diff --git a/TelegramCore/WebpagePreview.swift b/TelegramCore/WebpagePreview.swift index ca8152b201..b312e2104c 100644 --- a/TelegramCore/WebpagePreview.swift +++ b/TelegramCore/WebpagePreview.swift @@ -25,7 +25,7 @@ public func webpagePreview(account: Account, url: String, webpageId: MediaId? = if case .Loaded = media.content { return .single(media) } else { - return .single(media) |> then(account.stateManager.updatedWebpage(media.webpageId) |> map { Optional($0) }) + return .single(media) |> then(account.stateManager.updatedWebpage(media.webpageId) |> map(Optional.init)) } } else { return .single(nil)