diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index 49c3dcb30e..06c4759f5e 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -362,16 +362,15 @@ D08F4A671E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A691E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; - D093D7EB206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */; }; - D093D7EC206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */; }; + D093D7EB206413C900BC3599 /* SecureIdIdentityValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7EA206413C900BC3599 /* SecureIdIdentityValue.swift */; }; + D093D7EC206413C900BC3599 /* SecureIdIdentityValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7EA206413C900BC3599 /* SecureIdIdentityValue.swift */; }; D093D7EE206413F600BC3599 /* SecureIdDataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */; }; D093D7EF206413F600BC3599 /* SecureIdDataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */; }; - D093D7F12064194600BC3599 /* SecureIdIdentityField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */; }; - D093D7F22064194600BC3599 /* SecureIdIdentityField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */; }; - D093D7F520641A4900BC3599 /* SecureIdPhoneField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */; }; - D093D7F620641A4900BC3599 /* SecureIdPhoneField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */; }; - D093D7F920641AA500BC3599 /* SecureIdEmailField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */; }; - D093D7FA20641AA500BC3599 /* SecureIdEmailField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */; }; + D093D7F520641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */; }; + D093D7F620641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */; }; + D093D7F920641AA500BC3599 /* SecureIdEmailValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */; }; + D093D7FA20641AA500BC3599 /* SecureIdEmailValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */; }; + D093D806206539D000BC3599 /* SaveSecureIdValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D093D805206539D000BC3599 /* SaveSecureIdValue.swift */; }; D099D7461EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */; }; D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */; }; D099D7491EEF418D00A3128C /* HistoryViewChannelStateValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */; }; @@ -852,11 +851,11 @@ D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localizations.swift; sourceTree = ""; }; D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; - D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPassportIdentity.swift; sourceTree = ""; }; + D093D7EA206413C900BC3599 /* SecureIdIdentityValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdIdentityValue.swift; sourceTree = ""; }; D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdDataTypes.swift; sourceTree = ""; }; - D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdIdentityField.swift; sourceTree = ""; }; - D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPhoneField.swift; sourceTree = ""; }; - D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdEmailField.swift; sourceTree = ""; }; + D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPhoneValue.swift; sourceTree = ""; }; + D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdEmailValue.swift; sourceTree = ""; }; + D093D805206539D000BC3599 /* SaveSecureIdValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveSecureIdValue.swift; sourceTree = ""; }; D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMessageStateVersionAttribute.swift; sourceTree = ""; }; D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryViewChannelStateValidation.swift; sourceTree = ""; }; D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = ""; }; @@ -1497,40 +1496,31 @@ name = Localization; sourceTree = ""; }; - D093D7E82064135300BC3599 /* Fields */ = { + D093D7E82064135300BC3599 /* Values */ = { isa = PBXGroup; children = ( D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */, D093D7E92064135A00BC3599 /* Identity */, - D093D7F320641A3F00BC3599 /* Phone */, - D093D7F720641A9600BC3599 /* Email */, + D093D7F320641A3F00BC3599 /* Other */, ); - name = Fields; + name = Values; sourceTree = ""; }; D093D7E92064135A00BC3599 /* Identity */ = { isa = PBXGroup; children = ( - D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */, - D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */, + D093D7EA206413C900BC3599 /* SecureIdIdentityValue.swift */, ); name = Identity; sourceTree = ""; }; - D093D7F320641A3F00BC3599 /* Phone */ = { + D093D7F320641A3F00BC3599 /* Other */ = { isa = PBXGroup; children = ( - D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */, + D093D7F420641A4900BC3599 /* SecureIdPhoneValue.swift */, + D093D7F820641AA500BC3599 /* SecureIdEmailValue.swift */, ); - name = Phone; - sourceTree = ""; - }; - D093D7F720641A9600BC3599 /* Email */ = { - isa = PBXGroup; - children = ( - D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */, - ); - name = Email; + name = Other; sourceTree = ""; }; D09D8BF71D4FAB1D0081DBEC = { @@ -1621,10 +1611,11 @@ D0BE303820619E9E00FBE6D8 /* Secure ID */ = { isa = PBXGroup; children = ( - D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */, D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */, D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */, - D093D7E82064135300BC3599 /* Fields */, + D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */, + D093D805206539D000BC3599 /* SaveSecureIdValue.swift */, + D093D7E82064135300BC3599 /* Values */, ); name = "Secure ID"; sourceTree = ""; @@ -1952,7 +1943,7 @@ D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */, D0FA8BA71E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */, D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */, - D093D7F920641AA500BC3599 /* SecureIdEmailField.swift in Sources */, + D093D7F920641AA500BC3599 /* SecureIdEmailValue.swift in Sources */, D0C44B611FC616E200227BE0 /* SearchGroupMembers.swift in Sources */, D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */, D018D3371E648ACF00C5E089 /* CreateChannel.swift in Sources */, @@ -2046,7 +2037,7 @@ D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */, D0FA8BAA1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */, D00D97C71E32901700E5C2B6 /* PeerInputActivity.swift in Sources */, - D093D7EB206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */, + D093D7EB206413C900BC3599 /* SecureIdIdentityValue.swift in Sources */, D0FA8BAD1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, D03B0CBF1D62234A00955575 /* Log.swift in Sources */, C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */, @@ -2082,7 +2073,7 @@ D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */, D00C7CCC1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */, D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */, - D093D7F520641A4900BC3599 /* SecureIdPhoneField.swift in Sources */, + D093D7F520641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */, D0B167231F9F972E00976B40 /* LoggingSettings.swift in Sources */, D0BC387B1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */, D0BB7C5A1E5C8074001527C3 /* ChannelParticipants.swift in Sources */, @@ -2103,6 +2094,7 @@ D0C26D6C1FE286C3004ABF18 /* FetchChatList.swift in Sources */, D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */, D0E35A121DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, + D093D806206539D000BC3599 /* SaveSecureIdValue.swift in Sources */, C239BE9C1E630CA700C2C453 /* UpdatePinnedMessage.swift in Sources */, D08CAA7D1ED77EE90000FDA8 /* LocalizationSettings.swift in Sources */, D0B844531DAC0773005F29E1 /* TelegramUserPresence.swift in Sources */, @@ -2156,7 +2148,6 @@ D021E0E21DB5401A00C6B04F /* StickerManagement.swift in Sources */, D0BC38701E40853E0044D6FE /* UpdatePeers.swift in Sources */, D0F3A8A81E82CD7D00B4C64C /* UpdatePeerChatInterfaceState.swift in Sources */, - D093D7F12064194600BC3599 /* SecureIdIdentityField.swift in Sources */, D03B0CE21D62249B00955575 /* InlineBotMessageAttribute.swift in Sources */, D0AB0B9A1D666520002C78E7 /* ManagedSynchronizePeerReadStates.swift in Sources */, D03B0D5B1D631A6900955575 /* Buffer.swift in Sources */, @@ -2223,7 +2214,6 @@ C26A37EF1E5E0C41006977AC /* ChannelParticipants.swift in Sources */, D00D343D1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */, D0C26D6A1FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */, - D093D7F22064194600BC3599 /* SecureIdIdentityField.swift in Sources */, D01C7F051EFC1C49008305F1 /* DeviceContact.swift in Sources */, D050F26A1E4A5B6D00988324 /* ManagedGlobalNotificationSettings.swift in Sources */, D050F26B1E4A5B6D00988324 /* ApplyMaxReadIndexInteractively.swift in Sources */, @@ -2344,10 +2334,10 @@ D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */, D07047B51F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */, D0448C8F1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */, - D093D7F620641A4900BC3599 /* SecureIdPhoneField.swift in Sources */, + D093D7F620641A4900BC3599 /* SecureIdPhoneValue.swift in Sources */, D0C26D6D1FE286C3004ABF18 /* FetchChatList.swift in Sources */, D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */, - D093D7FA20641AA500BC3599 /* SecureIdEmailField.swift in Sources */, + D093D7FA20641AA500BC3599 /* SecureIdEmailValue.swift in Sources */, D05A32E21E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */, D0613FD01E60520700202CDB /* ChannelMembers.swift in Sources */, D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */, @@ -2463,7 +2453,7 @@ D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */, D058E0D21E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */, D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */, - D093D7EC206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */, + D093D7EC206413C900BC3599 /* SecureIdIdentityValue.swift in Sources */, D0FA8BBA1E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */, D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */, D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, diff --git a/TelegramCore/AccessSecureId.swift b/TelegramCore/AccessSecureId.swift index 29af8fe48a..3a67a82d68 100644 --- a/TelegramCore/AccessSecureId.swift +++ b/TelegramCore/AccessSecureId.swift @@ -15,11 +15,58 @@ private enum GenerateSecureSecretError { case generic } -func decryptedSecureSecret(encryptedSecretData: Data, password: String) -> Data? { +func encryptSecureData(key: Data, iv: Data, data: Data, decrypt: Bool) -> Data? { + if data.count % 16 != 0 { + return nil + } + + var processedData = Data(count: data.count) + guard processedData.withUnsafeMutableBytes({ (processedDataBytes: UnsafeMutablePointer) -> Bool in + return key.withUnsafeBytes { (keyBytes: UnsafePointer) -> Bool in + return iv.withUnsafeBytes { (ivBytes: UnsafePointer) -> Bool in + return data.withUnsafeBytes { (dataBytes: UnsafePointer) -> Bool in + var processedCount: Int = 0 + let result = CCCrypt(CCOperation(decrypt ? kCCDecrypt : kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128), 0, keyBytes, key.count, ivBytes, dataBytes, data.count, processedDataBytes, processedData.count, &processedCount) + if result != kCCSuccess { + return false + } + if processedCount != processedData.count { + return false + } + return true + } + } + } + }) else { + return nil + } + + return processedData +} + +func verifySecureSecret(_ data: Data) -> Bool { + guard data.withUnsafeBytes({ (bytes: UnsafePointer) -> Bool in + var checksum: UInt32 = 0 + for i in 0 ..< data.count { + checksum += UInt32(bytes.advanced(by: i).pointee) + checksum = checksum % 255 + } + if checksum == 239 { + return true + } else { + return false + } + }) else { + return false + } + return true +} + +func decryptedSecureSecret(encryptedSecretData: Data, password: String, salt: Data, hash: Int64) -> Data? { guard let passwordData = password.data(using: .utf8) else { return nil } - let passwordHash = sha512Digest(passwordData) + let passwordHash = sha512Digest(salt + passwordData + salt) let secretKey = passwordHash.subdata(in: 0 ..< 32) let iv = passwordHash.subdata(in: 32 ..< (32 + 16)) @@ -45,30 +92,45 @@ func decryptedSecureSecret(encryptedSecretData: Data, password: String) -> Data? return nil } - guard decryptedSecret.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in - var checksum: UInt32 = 0 - for i in 0 ..< decryptedSecret.count { - checksum += UInt32(bytes.advanced(by: i).pointee) - checksum = checksum % 255 - } - if checksum == 239 { - return true - } else { - return false - } - }) else { + if !verifySecureSecret(decryptedSecret) { + return nil + } + + let secretHashData = sha256Digest(decryptedSecret) + var secretHash: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) + } + + if secretHash != hash { return nil } return decryptedSecret } -func encryptedSecureSecret(secretData: Data, password: String) -> Data? { +func encryptedSecureSecret(secretData: Data, password: String, inputSalt: Data) -> (data: Data, salt: Data, hash: Int64)? { + let secretHashData = sha256Digest(secretData) + var secretHash: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) + } + guard let passwordData = password.data(using: .utf8) else { return nil } - let passwordHash = sha512Digest(passwordData) + var randomSalt = Data(count: 8) + guard randomSalt.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in + let result = SecRandomCopyBytes(nil, randomSalt.count, bytes) + return result == errSecSuccess + }) else { + return nil + } + + let secretSalt = inputSalt + randomSalt + + let passwordHash = sha512Digest(secretSalt + passwordData + secretSalt) let secretKey = passwordHash.subdata(in: 0 ..< 32) let iv = passwordHash.subdata(in: 32 ..< (32 + 16)) @@ -94,20 +156,20 @@ func encryptedSecureSecret(secretData: Data, password: String) -> Data? { return nil } - if decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: password) != secretData { + if decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: password, salt: secretSalt, hash: secretHash) != secretData { return nil } - return encryptedSecret + return (encryptedSecret, secretSalt, secretHash) } -private func generateSecureSecret(network: Network, password: String) -> Signal { +func generateSecureSecretData() -> Data? { var secretData = Data(count: 32) guard secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in let copyResult = SecRandomCopyBytes(nil, 32, bytes) return copyResult == errSecSuccess }) else { - return .fail(.generic) + return nil } secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) in @@ -136,12 +198,15 @@ private func generateSecureSecret(network: Network, password: String) -> Signal< } } }) - - guard let encryptedSecret = encryptedSecureSecret(secretData: secretData, password: password) else { + return secretData +} + +private func generateSecureSecret(network: Network, password: String) -> Signal { + guard let secretData = generateSecureSecretData() else { return .fail(.generic) } - return updateTwoStepVerificationSecureSecret(network: network, password: password, updatedSecret: encryptedSecret) + return updateTwoStepVerificationSecureSecret(network: network, password: password, secret: secretData) |> mapError { _ -> GenerateSecureSecretError in return .generic } @@ -152,6 +217,7 @@ private func generateSecureSecret(network: Network, password: String) -> Signal< public struct SecureIdAccessContext { let secret: Data + let hash: Int64 } public enum SecureIdAccessError { @@ -167,8 +233,8 @@ public func accessSecureId(network: Network, password: String) -> Signal mapToSignal { settings -> Signal in if let secureSecret = settings.secureSecret { - if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: secureSecret, password: "q") { //password - return .single(SecureIdAccessContext(secret: decryptedSecret)) + if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: secureSecret.data, password: password, salt: secureSecret.salt, hash: secureSecret.hash) { + return .single(SecureIdAccessContext(secret: decryptedSecret, hash: secureSecret.hash)) } else { return .fail(.secretPasswordMismatch) } @@ -178,7 +244,12 @@ public func accessSecureId(network: Network, password: String) -> Signal map { decryptedSecret in - return SecureIdAccessContext(secret: decryptedSecret) + let secretHashData = sha256Digest(decryptedSecret) + var secretHash: Int64 = 0 + secretHashData.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&secretHash, bytes.advanced(by: secretHashData.count - 8), 8) + } + return SecureIdAccessContext(secret: decryptedSecret, hash: secretHash) } } } diff --git a/TelegramCore/Account.swift b/TelegramCore/Account.swift index 1b587a9071..47434b47af 100644 --- a/TelegramCore/Account.swift +++ b/TelegramCore/Account.swift @@ -342,20 +342,47 @@ public struct TwoStepAuthData { public let currentHint: String? public let unconfirmedEmailPattern: String? public let secretRandom: Data + public let nextSecureSalt: Data } public func twoStepAuthData(_ network: Network) -> Signal { return network.request(Api.functions.account.getPassword()) |> map { config -> TwoStepAuthData in switch config { - case let .noPassword(newSalt, secretRandom, emailUnconfirmedPattern): - return TwoStepAuthData(nextSalt: newSalt.makeData(), currentSalt: nil, hasRecovery: false, currentHint: nil, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secretRandom.makeData()) - case let .password(currentSalt, newSalt, secretRandom, hint, hasRecovery, emailUnconfirmedPattern): - return TwoStepAuthData(nextSalt: newSalt.makeData(), currentSalt: currentSalt.makeData(), hasRecovery: hasRecovery == .boolTrue, currentHint: hint, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secretRandom.makeData()) + case let .noPassword(newSalt, newSecureSalt, secretRandom, emailUnconfirmedPattern): + return TwoStepAuthData(nextSalt: newSalt.makeData(), currentSalt: nil, hasRecovery: false, currentHint: nil, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secretRandom.makeData(), nextSecureSalt: newSecureSalt.makeData()) + case let .password(currentSalt, newSalt, newSecureSalt, secretRandom, hint, hasRecovery, emailUnconfirmedPattern): + return TwoStepAuthData(nextSalt: newSalt.makeData(), currentSalt: currentSalt.makeData(), hasRecovery: hasRecovery == .boolTrue, currentHint: hint, unconfirmedEmailPattern: emailUnconfirmedPattern, secretRandom: secretRandom.makeData(), nextSecureSalt: newSecureSalt.makeData()) } } } +func hexString(_ data: Data) -> String { + let hexString = NSMutableString() + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + for i in 0 ..< data.count { + hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee)) + } + } + + return hexString as String +} + +func dataWithHexString(_ string: String) -> Data { + var hex = string + var data = Data() + while hex.count > 0 { + let subIndex = hex.index(hex.startIndex, offsetBy: 2) + let c = String(hex[.. Data { var res = Data() res.count = Int(CC_SHA1_DIGEST_LENGTH) @@ -467,6 +494,81 @@ public struct AccountRunningImportantTasks: OptionSet { public static let pendingMessages = AccountRunningImportantTasks(rawValue: 1 << 1) } +private struct MasterNotificationKey { + let id: Data + let data: Data +} + +private func masterNotificationsKey(account: Account, ignoreDisabled: Bool) -> Signal { + if let key = account.masterNotificationKey.with({ $0 }) { + //return .single(key) + } + + return account.postbox.modify(ignoreDisabled: ignoreDisabled, { modifier -> MasterNotificationKey in + if let value = modifier.keychainEntryForKey("master-notification-secret"), !value.isEmpty { + let authKeyHash = sha1Digest(value) + let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count) + let keyData = MasterNotificationKey(id: authKeyId, data: value) + let _ = account.masterNotificationKey.swap(keyData) + return keyData + } else { + var secretData = Data(count: 256) + if !secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer) -> Bool in + let copyResult = SecRandomCopyBytes(nil, secretData.count, bytes) + return copyResult == errSecSuccess + }) { + assertionFailure() + } + + modifier.setKeychainEntry(secretData, forKey: "master-notification-secret") + let authKeyHash = sha1Digest(secretData) + let authKeyId = authKeyHash.subdata(in: authKeyHash.count - 8 ..< authKeyHash.count) + let keyData = MasterNotificationKey(id: authKeyId, data: secretData) + let _ = account.masterNotificationKey.swap(keyData) + return keyData + } + }) +} + +public func decryptedNotificationPayload(account: Account, data: Data) -> Signal { + return masterNotificationsKey(account: account, ignoreDisabled: true) + |> map { secret -> Data? in + if data.subdata(in: 0 ..< 8) != secret.id { + return nil + } + + let x = 8 + let msgKey = data.subdata(in: 8 ..< (8 + 16)) + let rawData = data.subdata(in: (8 + 16) ..< data.count) + let sha256_a = sha256Digest(msgKey + secret.data.subdata(in: x ..< (x + 36))) + let sha256_b = sha256Digest(secret.data.subdata(in: (40 + x) ..< (40 + x + 36)) + msgKey) + let aesKey = sha256_a.subdata(in: 0 ..< 8) + sha256_b.subdata(in: 8 ..< (8 + 16)) + sha256_a.subdata(in: 24 ..< (24 + 8)) + let aesIv = sha256_b.subdata(in: 0 ..< 8) + sha256_a.subdata(in: 8 ..< (8 + 16)) + sha256_b.subdata(in: 24 ..< (24 + 8)) + + guard let data = MTAesDecrypt(rawData, aesKey, aesIv), data.count > 4 else { + return nil + } + + var dataLength: Int32 = 0 + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&dataLength, bytes, 4) + } + + if dataLength < 0 || dataLength > data.count - 4 { + return nil + } + + let checkMsgKeyLarge = sha256Digest(secret.data.subdata(in: (88 + x) ..< (88 + x + 32)) + data) + let checkMsgKey = checkMsgKeyLarge.subdata(in: 8 ..< (8 + 16)) + + if checkMsgKey != msgKey { + return nil + } + + return data.subdata(in: 4 ..< (4 + Int(dataLength))) + } +} + public class Account { public let id: AccountRecordId public let basePath: String @@ -524,6 +626,8 @@ public class Account { return self._importantTasksRunning.get() } + fileprivate let masterNotificationKey = Atomic(value: nil) + var transformOutgoingMessageMedia: TransformOutgoingMessageMedia? public init(id: AccountRecordId, basePath: String, testingEnvironment: Bool, postbox: Postbox, network: Network, peerId: PeerId, auxiliaryMethods: AccountAuxiliaryMethods) { @@ -588,11 +692,15 @@ public class Account { #if DEBUG appSandbox = .boolTrue #endif - return network.request(Api.functions.account.registerDevice(tokenType: 1, token: tokenString, appSandbox: appSandbox, secret: Buffer(), otherUids: [])) + + return masterNotificationsKey(account: self, ignoreDisabled: false) + |> mapToSignal { secret -> Signal in + return network.request(Api.functions.account.registerDevice(tokenType: 1, token: tokenString, appSandbox: appSandbox, secret: Buffer(data: secret.data), otherUids: [])) |> retryRequest |> mapToSignal { _ -> Signal in return .complete() } + } } self.notificationTokenDisposable.set(appliedNotificationToken.start()) @@ -612,11 +720,14 @@ public class Account { appSandbox = .boolTrue #endif - return network.request(Api.functions.account.registerDevice(tokenType: 9, token: tokenString, appSandbox: appSandbox, secret: Buffer(), otherUids: [])) + return masterNotificationsKey(account: self, ignoreDisabled: false) + |> mapToSignal { secret -> Signal in + return network.request(Api.functions.account.registerDevice(tokenType: 9, token: tokenString, appSandbox: appSandbox, secret: Buffer(data: secret.data), otherUids: [])) |> retryRequest |> mapToSignal { _ -> Signal in return .complete() } + } } self.voipTokenDisposable.set(appliedVoipToken.start()) diff --git a/TelegramCore/Api.swift b/TelegramCore/Api.swift index 5e950c1d90..ce833b78ef 100644 --- a/TelegramCore/Api.swift +++ b/TelegramCore/Api.swift @@ -92,7 +92,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-292807034] = { return Api.InputChannel.parse_inputChannelEmpty($0) } dict[-1343524562] = { return Api.InputChannel.parse_inputChannel($0) } dict[98092748] = { return Api.DcOption.parse_dcOption($0) } - dict[-118752193] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } + dict[1223432016] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } dict[292985073] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } @@ -212,6 +212,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1893427255] = { return Api.Update.parse_updateChannelAvailableMessages($0) } dict[433225532] = { return Api.Update.parse_updateDialogPinned($0) } dict[-364071333] = { return Api.Update.parse_updatePinnedDialogs($0) } + dict[1278258960] = { return Api.Update.parse_updateBotSecureValues($0) } dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) } dict[-1557620115] = { return Api.ChannelParticipant.parse_channelParticipantSelf($0) } @@ -220,7 +221,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[573315206] = { return Api.ChannelParticipant.parse_channelParticipantBanned($0) } dict[471043349] = { return Api.contacts.Blocked.parse_blocked($0) } dict[-1878523231] = { return Api.contacts.Blocked.parse_blockedSlice($0) } - dict[-2090391602] = { return Api.account.AuthorizationResult.parse_authorizationResult($0) } dict[-55902537] = { return Api.InputDialogPeer.parse_inputDialogPeer($0) } dict[-994444869] = { return Api.Error.parse_error($0) } dict[-1560655744] = { return Api.KeyboardButton.parse_keyboardButton($0) } @@ -269,10 +269,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[864077702] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaAuto($0) } dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) } dict[1434820921] = { return Api.StickerSet.parse_stickerSet($0) } - dict[71383901] = { return Api.AuthFieldType.parse_authFieldTypeIdentity($0) } - dict[1673252083] = { return Api.AuthFieldType.parse_authFieldTypeAddress($0) } - dict[-1251925761] = { return Api.AuthFieldType.parse_authFieldTypePhone($0) } - dict[1288305926] = { return Api.AuthFieldType.parse_authFieldTypeEmail($0) } dict[539045032] = { return Api.photos.Photo.parse_photo($0) } dict[-208488460] = { return Api.InputContact.parse_inputPhoneContact($0) } dict[-1419371685] = { return Api.TopPeerCategory.parse_topPeerCategoryBotsPM($0) } @@ -290,6 +286,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1928391342] = { return Api.InputDocument.parse_inputDocumentEmpty($0) } dict[410618194] = { return Api.InputDocument.parse_inputDocument($0) } dict[2131196633] = { return Api.contacts.ResolvedPeer.parse_resolvedPeer($0) } + dict[640352564] = { return Api.SecureData.parse_secureData($0) } dict[-1771768449] = { return Api.InputMedia.parse_inputMediaEmpty($0) } dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) } dict[-1494984313] = { return Api.InputMedia.parse_inputMediaContact($0) } @@ -344,15 +341,17 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-714643696] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionParticipantToggleAdmin($0) } dict[-1312568665] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionChangeStickerSet($0) } dict[1599903217] = { return Api.ChannelAdminLogEventAction.parse_channelAdminLogEventActionTogglePreHistoryHidden($0) } + dict[1630373599] = { return Api.SecureValueVerified.parse_secureValueVerified($0) } dict[-543777747] = { return Api.auth.ExportedAuthorization.parse_exportedAuthorization($0) } dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } - dict[550411865] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } + dict[-447502641] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } 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[1652281101] = { return Api.InputSecureValue.parse_inputSecureValueData($0) } - dict[-498101146] = { return Api.InputSecureValue.parse_inputSecureValueFile($0) } - dict[-1789258565] = { return Api.InputSecureValue.parse_inputSecureValueText($0) } + dict[-1373121018] = { return Api.InputSecureValue.parse_inputSecureValueIdentity($0) } + dict[-1040763931] = { return Api.InputSecureValue.parse_inputSecureValueAddress($0) } + dict[337510584] = { return Api.InputSecureValue.parse_inputSecureValuePhone($0) } + dict[767646618] = { return Api.InputSecureValue.parse_inputSecureValueEmail($0) } dict[-313079300] = { return Api.account.WebAuthorizations.parse_webAuthorizations($0) } dict[-236044656] = { return Api.help.TermsOfService.parse_termsOfService($0) } dict[1490799288] = { return Api.ReportReason.parse_inputReportReasonSpam($0) } @@ -381,11 +380,11 @@ 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[-254884128] = { return Api.SecureValue.parse_secureValueEmpty($0) } - dict[1815868021] = { return Api.SecureValue.parse_secureValueData($0) } - dict[-1589272232] = { return Api.SecureValue.parse_secureValueFile($0) } - dict[464747747] = { return Api.SecureValue.parse_secureValueText($0) } - dict[239871607] = { return Api.SecureValueHash.parse_secureValueHash($0) } + dict[-1496766547] = { return Api.SecureValue.parse_secureValueIdentity($0) } + dict[1956698012] = { return Api.SecureValue.parse_secureValueAddress($0) } + dict[-1580563202] = { return Api.SecureValue.parse_secureValuePhone($0) } + dict[-992254599] = { return Api.SecureValue.parse_secureValueEmail($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) } dict[-1182234929] = { return Api.InputUser.parse_inputUserEmpty($0) } @@ -393,6 +392,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } dict[-1908433218] = { return Api.Page.parse_pagePart($0) } dict[1433323434] = { return Api.Page.parse_pageFull($0) } + dict[1653596458] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } dict[157948117] = { return Api.upload.File.parse_file($0) } dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } dict[182649427] = { return Api.MessageRange.parse_messageRange($0) } @@ -424,7 +424,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[480546647] = { return Api.InputChatPhoto.parse_inputChatPhotoEmpty($0) } dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } - dict[-310262820] = { return Api.AuthField.parse_authField($0) } dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } @@ -504,8 +503,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } dict[-84416311] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonBusy($0) } dict[-1910892683] = { return Api.NearestDc.parse_nearestDc($0) } - dict[-186602735] = { return Api.account.SecureValueResult.parse_secureValueResultSaved($0) } - dict[-1852661285] = { return Api.account.SecureValueResult.parse_secureValueVerificationNeeded($0) } dict[-1916114267] = { return Api.photos.Photos.parse_photos($0) } dict[352657236] = { return Api.photos.Photos.parse_photosSlice($0) } dict[2010127419] = { return Api.contacts.ImportedContacts.parse_importedContacts($0) } @@ -553,15 +550,19 @@ 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[1083800433] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } + dict[-1919033877] = { 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) } dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) } dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) } dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } - dict[-933006915] = { return Api.account.Password.parse_noPassword($0) } - dict[1240452341] = { return Api.account.Password.parse_password($0) } + dict[937056458] = { return Api.SecureValueType.parse_secureValueTypeIdentity($0) } + dict[-874308058] = { return Api.SecureValueType.parse_secureValueTypeAddress($0) } + dict[-1289704741] = { return Api.SecureValueType.parse_secureValueTypePhone($0) } + dict[-1908627474] = { return Api.SecureValueType.parse_secureValueTypeEmail($0) } + dict[1587643126] = { return Api.account.Password.parse_noPassword($0) } + dict[-798203965] = { 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) } @@ -790,8 +791,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.contacts.Blocked: _1.serialize(buffer, boxed) - case let _1 as Api.account.AuthorizationResult: - _1.serialize(buffer, boxed) case let _1 as Api.InputDialogPeer: _1.serialize(buffer, boxed) case let _1 as Api.Error: @@ -828,8 +827,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.StickerSet: _1.serialize(buffer, boxed) - case let _1 as Api.AuthFieldType: - _1.serialize(buffer, boxed) case let _1 as Api.photos.Photo: _1.serialize(buffer, boxed) case let _1 as Api.InputContact: @@ -848,6 +845,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.contacts.ResolvedPeer: _1.serialize(buffer, boxed) + case let _1 as Api.SecureData: + _1.serialize(buffer, boxed) case let _1 as Api.InputMedia: _1.serialize(buffer, boxed) case let _1 as Api.InputPeer: @@ -874,6 +873,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ChannelAdminLogEventAction: _1.serialize(buffer, boxed) + case let _1 as Api.SecureValueVerified: + _1.serialize(buffer, boxed) case let _1 as Api.auth.ExportedAuthorization: _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedHistory: @@ -930,6 +931,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.Page: _1.serialize(buffer, boxed) + case let _1 as Api.SecureCredentialsEncrypted: + _1.serialize(buffer, boxed) case let _1 as Api.upload.File: _1.serialize(buffer, boxed) case let _1 as Api.MessageRange: @@ -968,8 +971,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.InputChatPhoto: _1.serialize(buffer, boxed) - case let _1 as Api.AuthField: - _1.serialize(buffer, boxed) case let _1 as Api.PaymentCharge: _1.serialize(buffer, boxed) case let _1 as Api.Updates: @@ -1036,8 +1037,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.NearestDc: _1.serialize(buffer, boxed) - case let _1 as Api.account.SecureValueResult: - _1.serialize(buffer, boxed) case let _1 as Api.photos.Photos: _1.serialize(buffer, boxed) case let _1 as Api.contacts.ImportedContacts: @@ -1086,6 +1085,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.AccountDaysTTL: _1.serialize(buffer, boxed) + case let _1 as Api.SecureValueType: + _1.serialize(buffer, boxed) case let _1 as Api.account.Password: _1.serialize(buffer, boxed) case let _1 as Api.InputBotInlineResult: @@ -5166,6 +5167,7 @@ public struct Api { case updateChannelAvailableMessages(channelId: Int32, availableMinId: Int32) case updateDialogPinned(flags: Int32, peer: Api.DialogPeer) case updatePinnedDialogs(flags: Int32, order: [Api.DialogPeer]?) + case updateBotSecureValues(userId: Int32, values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -5713,6 +5715,18 @@ public struct Api { item.serialize(buffer, true) }} break + case .updateBotSecureValues(let userId, let values, let credentials): + if boxed { + buffer.appendInt32(1278258960) + } + serializeInt32(userId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(values.count)) + for item in values { + item.serialize(buffer, true) + } + credentials.serialize(buffer, true) + break } } fileprivate static func parse_updateNewMessage(_ reader: BufferReader) -> Update? { @@ -6803,6 +6817,27 @@ public struct Api { return nil } } + fileprivate static func parse_updateBotSecureValues(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.SecureValue]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) + } + var _3: Api.SecureCredentialsEncrypted? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.SecureCredentialsEncrypted + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateBotSecureValues(userId: _1!, values: _2!, credentials: _3!) + } + else { + return nil + } + } } @@ -7259,7 +7294,7 @@ public struct Api { public enum SecureFile { case secureFileEmpty - case secureFile(id: Int64, accessHash: Int64, size: Int32, dcId: Int32, fileHash: String) + case secureFile(id: Int64, accessHash: Int64, size: Int32, dcId: Int32, fileHash: Buffer) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -7277,7 +7312,7 @@ public struct Api { serializeInt64(accessHash, buffer: buffer, boxed: false) serializeInt32(size, buffer: buffer, boxed: false) serializeInt32(dcId, buffer: buffer, boxed: false) - serializeString(fileHash, buffer: buffer, boxed: false) + serializeBytes(fileHash, buffer: buffer, boxed: false) break } } @@ -7293,8 +7328,8 @@ public struct Api { _3 = reader.readInt32() var _4: Int32? _4 = reader.readInt32() - var _5: String? - _5 = parseString(reader) + var _5: Buffer? + _5 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -8201,56 +8236,6 @@ public struct Api { } - } - - public enum AuthFieldType { - case authFieldTypeIdentity - case authFieldTypeAddress - case authFieldTypePhone - case authFieldTypeEmail - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .authFieldTypeIdentity: - if boxed { - buffer.appendInt32(71383901) - } - - break - case .authFieldTypeAddress: - if boxed { - buffer.appendInt32(1673252083) - } - - break - case .authFieldTypePhone: - if boxed { - buffer.appendInt32(-1251925761) - } - - break - case .authFieldTypeEmail: - if boxed { - buffer.appendInt32(1288305926) - } - - break - } - } - fileprivate static func parse_authFieldTypeIdentity(_ reader: BufferReader) -> AuthFieldType? { - return Api.AuthFieldType.authFieldTypeIdentity - } - fileprivate static func parse_authFieldTypeAddress(_ reader: BufferReader) -> AuthFieldType? { - return Api.AuthFieldType.authFieldTypeAddress - } - fileprivate static func parse_authFieldTypePhone(_ reader: BufferReader) -> AuthFieldType? { - return Api.AuthFieldType.authFieldTypePhone - } - fileprivate static func parse_authFieldTypeEmail(_ reader: BufferReader) -> AuthFieldType? { - return Api.AuthFieldType.authFieldTypeEmail - } - - } public enum InputContact { @@ -8451,6 +8436,38 @@ public struct Api { } + } + + public enum SecureData { + case secureData(data: Buffer, dataHash: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureData(let data, let dataHash): + if boxed { + buffer.appendInt32(640352564) + } + serializeBytes(data, buffer: buffer, boxed: false) + serializeBytes(dataHash, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_secureData(_ reader: BufferReader) -> SecureData? { + var _1: Buffer? + _1 = parseBytes(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.SecureData.secureData(data: _1!, dataHash: _2!) + } + else { + return nil + } + } + + } public enum InputMedia { @@ -9659,6 +9676,38 @@ public struct Api { } + } + + public enum SecureValueVerified { + case secureValueVerified(date: Int32, provider: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValueVerified(let date, let provider): + if boxed { + buffer.appendInt32(1630373599) + } + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(provider, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_secureValueVerified(_ reader: BufferReader) -> SecureValueVerified? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.SecureValueVerified.secureValueVerified(date: _1!, provider: _2!) + } + else { + return nil + } + } + + } public enum LabeledPrice { @@ -9694,73 +9743,66 @@ public struct Api { } public enum InputSecureValue { - case inputSecureValueData(name: String, data: Buffer, hash: String, secret: Buffer) - case inputSecureValueFile(name: String, file: [Api.InputSecureFile], hash: String, secret: Buffer) - case inputSecureValueText(name: String, text: String, hash: String) + case inputSecureValueIdentity(data: Api.SecureData, files: [Api.InputSecureFile], secret: Buffer, hash: Buffer) + case inputSecureValueAddress(data: Api.SecureData, files: [Api.InputSecureFile], secret: Buffer, hash: Buffer) + case inputSecureValuePhone(phone: String, hash: Buffer) + case inputSecureValueEmail(email: String, hash: Buffer) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .inputSecureValueData(let name, let data, let hash, let secret): + case .inputSecureValueIdentity(let data, let files, let secret, let hash): if boxed { - buffer.appendInt32(1652281101) + buffer.appendInt32(-1373121018) } - serializeString(name, buffer: buffer, boxed: false) - serializeBytes(data, buffer: buffer, boxed: false) - serializeString(hash, buffer: buffer, boxed: false) - serializeBytes(secret, buffer: buffer, boxed: false) - break - case .inputSecureValueFile(let name, let file, let hash, let secret): - if boxed { - buffer.appendInt32(-498101146) - } - serializeString(name, buffer: buffer, boxed: false) + data.serialize(buffer, true) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(file.count)) - for item in file { + buffer.appendInt32(Int32(files.count)) + for item in files { item.serialize(buffer, true) } - serializeString(hash, buffer: buffer, boxed: false) serializeBytes(secret, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) break - case .inputSecureValueText(let name, let text, let hash): + case .inputSecureValueAddress(let data, let files, let secret, let hash): if boxed { - buffer.appendInt32(-1789258565) + buffer.appendInt32(-1040763931) } - serializeString(name, buffer: buffer, boxed: false) - serializeString(text, buffer: buffer, boxed: false) - serializeString(hash, buffer: buffer, boxed: false) + data.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(files.count)) + for item in files { + item.serialize(buffer, true) + } + serializeBytes(secret, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + break + case .inputSecureValuePhone(let phone, let hash): + if boxed { + buffer.appendInt32(337510584) + } + serializeString(phone, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + break + case .inputSecureValueEmail(let email, let hash): + if boxed { + buffer.appendInt32(767646618) + } + serializeString(email, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) break } } - fileprivate static func parse_inputSecureValueData(_ reader: BufferReader) -> InputSecureValue? { - var _1: String? - _1 = parseString(reader) - var _2: Buffer? - _2 = parseBytes(reader) - var _3: String? - _3 = parseString(reader) - var _4: Buffer? - _4 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.InputSecureValue.inputSecureValueData(name: _1!, data: _2!, hash: _3!, secret: _4!) + fileprivate static func parse_inputSecureValueIdentity(_ reader: BufferReader) -> InputSecureValue? { + var _1: Api.SecureData? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureData } - else { - return nil - } - } - fileprivate static func parse_inputSecureValueFile(_ reader: BufferReader) -> InputSecureValue? { - var _1: String? - _1 = parseString(reader) var _2: [Api.InputSecureFile]? if let _ = reader.readInt32() { _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) } - var _3: String? - _3 = parseString(reader) + var _3: Buffer? + _3 = parseBytes(reader) var _4: Buffer? _4 = parseBytes(reader) let _c1 = _1 != nil @@ -9768,24 +9810,59 @@ public struct Api { let _c3 = _3 != nil let _c4 = _4 != nil if _c1 && _c2 && _c3 && _c4 { - return Api.InputSecureValue.inputSecureValueFile(name: _1!, file: _2!, hash: _3!, secret: _4!) + return Api.InputSecureValue.inputSecureValueIdentity(data: _1!, files: _2!, secret: _3!, hash: _4!) } else { return nil } } - fileprivate static func parse_inputSecureValueText(_ reader: BufferReader) -> InputSecureValue? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) + fileprivate static func parse_inputSecureValueAddress(_ reader: BufferReader) -> InputSecureValue? { + var _1: Api.SecureData? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureData + } + var _2: [Api.InputSecureFile]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputSecureFile.self) + } + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Buffer? + _4 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.InputSecureValue.inputSecureValueText(name: _1!, text: _2!, hash: _3!) + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputSecureValue.inputSecureValueAddress(data: _1!, files: _2!, secret: _3!, hash: _4!) + } + else { + return nil + } + } + fileprivate static func parse_inputSecureValuePhone(_ reader: BufferReader) -> InputSecureValue? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputSecureValue.inputSecureValuePhone(phone: _1!, hash: _2!) + } + else { + return nil + } + } + fileprivate static func parse_inputSecureValueEmail(_ reader: BufferReader) -> InputSecureValue? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputSecureValue.inputSecureValueEmail(email: _1!, hash: _2!) } else { return nil @@ -10336,116 +10413,166 @@ public struct Api { } public enum SecureValue { - case secureValueEmpty(name: String) - case secureValueData(name: String, data: Buffer, hash: String, secret: Buffer) - case secureValueFile(name: String, file: [Api.SecureFile], hash: String, secret: Buffer) - case secureValueText(name: String, text: String, hash: String) + case secureValueIdentity(flags: Int32, data: Api.SecureData, files: [Api.SecureFile], secret: Buffer, hash: Buffer, verified: Api.SecureValueVerified?) + case secureValueAddress(flags: Int32, data: Api.SecureData, files: [Api.SecureFile], secret: Buffer, hash: Buffer, verified: Api.SecureValueVerified?) + case secureValuePhone(flags: Int32, phone: String, hash: Buffer, verified: Api.SecureValueVerified?) + case secureValueEmail(flags: Int32, email: String, hash: Buffer, verified: Api.SecureValueVerified?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .secureValueEmpty(let name): + case .secureValueIdentity(let flags, let data, let files, let secret, let hash, let verified): if boxed { - buffer.appendInt32(-254884128) + buffer.appendInt32(-1496766547) } - serializeString(name, buffer: buffer, boxed: false) - break - case .secureValueData(let name, let data, let hash, let secret): - if boxed { - buffer.appendInt32(1815868021) - } - serializeString(name, buffer: buffer, boxed: false) - serializeBytes(data, buffer: buffer, boxed: false) - serializeString(hash, buffer: buffer, boxed: false) - serializeBytes(secret, buffer: buffer, boxed: false) - break - case .secureValueFile(let name, let file, let hash, let secret): - if boxed { - buffer.appendInt32(-1589272232) - } - serializeString(name, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + data.serialize(buffer, true) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(file.count)) - for item in file { + buffer.appendInt32(Int32(files.count)) + for item in files { item.serialize(buffer, true) } - serializeString(hash, buffer: buffer, boxed: false) serializeBytes(secret, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {verified!.serialize(buffer, true)} break - case .secureValueText(let name, let text, let hash): + case .secureValueAddress(let flags, let data, let files, let secret, let hash, let verified): if boxed { - buffer.appendInt32(464747747) + buffer.appendInt32(1956698012) } - serializeString(name, buffer: buffer, boxed: false) - serializeString(text, buffer: buffer, boxed: false) - serializeString(hash, buffer: buffer, boxed: false) + serializeInt32(flags, buffer: buffer, boxed: false) + data.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(files.count)) + for item in files { + item.serialize(buffer, true) + } + serializeBytes(secret, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {verified!.serialize(buffer, true)} + break + case .secureValuePhone(let flags, let phone, let hash, let verified): + if boxed { + buffer.appendInt32(-1580563202) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(phone, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {verified!.serialize(buffer, true)} + break + case .secureValueEmail(let flags, let email, let hash, let verified): + if boxed { + buffer.appendInt32(-992254599) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(email, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {verified!.serialize(buffer, true)} break } } - fileprivate static func parse_secureValueEmpty(_ reader: BufferReader) -> SecureValue? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.SecureValue.secureValueEmpty(name: _1!) + fileprivate static func parse_secureValueIdentity(_ reader: BufferReader) -> SecureValue? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureData? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureData } - else { - return nil - } - } - fileprivate static func parse_secureValueData(_ reader: BufferReader) -> SecureValue? { - var _1: String? - _1 = parseString(reader) - var _2: Buffer? - _2 = parseBytes(reader) - var _3: String? - _3 = parseString(reader) - var _4: Buffer? - _4 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.SecureValue.secureValueData(name: _1!, data: _2!, hash: _3!, secret: _4!) - } - else { - return nil - } - } - fileprivate static func parse_secureValueFile(_ reader: BufferReader) -> SecureValue? { - var _1: String? - _1 = parseString(reader) - var _2: [Api.SecureFile]? + var _3: [Api.SecureFile]? if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) } - var _3: String? - _3 = parseString(reader) var _4: Buffer? _4 = parseBytes(reader) + var _5: Buffer? + _5 = parseBytes(reader) + var _6: Api.SecureValueVerified? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.SecureValueVerified + } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.SecureValue.secureValueFile(name: _1!, file: _2!, hash: _3!, secret: _4!) + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.SecureValue.secureValueIdentity(flags: _1!, data: _2!, files: _3!, secret: _4!, hash: _5!, verified: _6) } else { return nil } } - fileprivate static func parse_secureValueText(_ reader: BufferReader) -> SecureValue? { - var _1: String? - _1 = parseString(reader) + fileprivate static func parse_secureValueAddress(_ reader: BufferReader) -> SecureValue? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.SecureData? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.SecureData + } + var _3: [Api.SecureFile]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureFile.self) + } + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Buffer? + _5 = parseBytes(reader) + var _6: Api.SecureValueVerified? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.SecureValueVerified + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.SecureValue.secureValueAddress(flags: _1!, data: _2!, files: _3!, secret: _4!, hash: _5!, verified: _6) + } + else { + return nil + } + } + fileprivate static func parse_secureValuePhone(_ reader: BufferReader) -> SecureValue? { + var _1: Int32? + _1 = reader.readInt32() var _2: String? _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Api.SecureValueVerified? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.SecureValueVerified + } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.SecureValue.secureValueText(name: _1!, text: _2!, hash: _3!) + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.SecureValue.secureValuePhone(flags: _1!, phone: _2!, hash: _3!, verified: _4) + } + else { + return nil + } + } + fileprivate static func parse_secureValueEmail(_ reader: BufferReader) -> SecureValue? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Api.SecureValueVerified? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.SecureValueVerified + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.SecureValue.secureValueEmail(flags: _1!, email: _2!, hash: _3!, verified: _4) } else { return nil @@ -10456,28 +10583,30 @@ public struct Api { } public enum SecureValueHash { - case secureValueHash(name: String, hash: String) + case secureValueHash(type: Api.SecureValueType, hash: Buffer) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .secureValueHash(let name, let hash): + case .secureValueHash(let type, let hash): if boxed { - buffer.appendInt32(239871607) + buffer.appendInt32(-316748368) } - serializeString(name, buffer: buffer, boxed: false) - serializeString(hash, buffer: buffer, boxed: false) + type.serialize(buffer, true) + serializeBytes(hash, buffer: buffer, boxed: false) break } } fileprivate static func parse_secureValueHash(_ reader: BufferReader) -> SecureValueHash? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) + var _1: Api.SecureValueType? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.SecureValueType + } + var _2: Buffer? + _2 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil if _c1 && _c2 { - return Api.SecureValueHash.secureValueHash(name: _1!, hash: _2!) + return Api.SecureValueHash.secureValueHash(type: _1!, hash: _2!) } else { return nil @@ -10667,6 +10796,42 @@ public struct Api { } + } + + public enum SecureCredentialsEncrypted { + case secureCredentialsEncrypted(data: Buffer, secret: Buffer, hash: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureCredentialsEncrypted(let data, let secret, let hash): + if boxed { + buffer.appendInt32(1653596458) + } + serializeBytes(data, buffer: buffer, boxed: false) + serializeBytes(secret, buffer: buffer, boxed: false) + serializeBytes(hash, buffer: buffer, boxed: false) + break + } + } + fileprivate static func parse_secureCredentialsEncrypted(_ reader: BufferReader) -> SecureCredentialsEncrypted? { + var _1: Buffer? + _1 = parseBytes(reader) + 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.SecureCredentialsEncrypted.secureCredentialsEncrypted(data: _1!, secret: _2!, hash: _3!) + } + else { + return nil + } + } + + } public enum MessageRange { @@ -11389,52 +11554,6 @@ public struct Api { } - } - - public enum AuthField { - case authField(flags: Int32, type: Api.AuthFieldType, data: Api.SecureValue, document: Api.SecureValue?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .authField(let flags, let type, let data, let document): - if boxed { - buffer.appendInt32(-310262820) - } - serializeInt32(flags, buffer: buffer, boxed: false) - type.serialize(buffer, true) - data.serialize(buffer, true) - if Int(flags) & Int(1 << 0) != 0 {document!.serialize(buffer, true)} - break - } - } - fileprivate static func parse_authField(_ reader: BufferReader) -> AuthField? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.AuthFieldType? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.AuthFieldType - } - var _3: Api.SecureValue? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.SecureValue - } - var _4: Api.SecureValue? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.SecureValue - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.AuthField.authField(flags: _1!, type: _2!, data: _3!, document: _4) - } - else { - return nil - } - } - - } public enum PaymentCharge { @@ -13258,7 +13377,7 @@ public struct Api { } public enum InputSecureFile { - case inputSecureFileUploaded(id: Int64, parts: Int32, md5Checksum: String, fileHash: String) + case inputSecureFileUploaded(id: Int64, parts: Int32, md5Checksum: String, fileHash: Buffer) case inputSecureFile(id: Int64, accessHash: Int64) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { @@ -13270,7 +13389,7 @@ public struct Api { serializeInt64(id, buffer: buffer, boxed: false) serializeInt32(parts, buffer: buffer, boxed: false) serializeString(md5Checksum, buffer: buffer, boxed: false) - serializeString(fileHash, buffer: buffer, boxed: false) + serializeBytes(fileHash, buffer: buffer, boxed: false) break case .inputSecureFile(let id, let accessHash): if boxed { @@ -13288,8 +13407,8 @@ public struct Api { _2 = reader.readInt32() var _3: String? _3 = parseString(reader) - var _4: String? - _4 = parseString(reader) + var _4: Buffer? + _4 = parseBytes(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -14491,6 +14610,56 @@ public struct Api { } + } + + public enum SecureValueType { + case secureValueTypeIdentity + case secureValueTypeAddress + case secureValueTypePhone + case secureValueTypeEmail + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .secureValueTypeIdentity: + if boxed { + buffer.appendInt32(937056458) + } + + break + case .secureValueTypeAddress: + if boxed { + buffer.appendInt32(-874308058) + } + + break + case .secureValueTypePhone: + if boxed { + buffer.appendInt32(-1289704741) + } + + break + case .secureValueTypeEmail: + if boxed { + buffer.appendInt32(-1908627474) + } + + break + } + } + fileprivate static func parse_secureValueTypeIdentity(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeIdentity + } + fileprivate static func parse_secureValueTypeAddress(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeAddress + } + fileprivate static func parse_secureValueTypePhone(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypePhone + } + fileprivate static func parse_secureValueTypeEmail(_ reader: BufferReader) -> SecureValueType? { + return Api.SecureValueType.secureValueTypeEmail + } + + } public enum InputBotInlineResult { @@ -18701,16 +18870,18 @@ public struct Api { } public enum PasswordSettings { - case passwordSettings(email: String, secureSecret: Buffer) + case passwordSettings(email: String, secureSalt: Buffer, secureSecret: Buffer, secureSecretHash: Int64) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .passwordSettings(let email, let secureSecret): + case .passwordSettings(let email, let secureSalt, let secureSecret, let secureSecretHash): if boxed { - buffer.appendInt32(-118752193) + buffer.appendInt32(1223432016) } serializeString(email, buffer: buffer, boxed: false) + serializeBytes(secureSalt, buffer: buffer, boxed: false) serializeBytes(secureSecret, buffer: buffer, boxed: false) + serializeInt64(secureSecretHash, buffer: buffer, boxed: false) break } } @@ -18719,50 +18890,16 @@ public struct Api { _1 = parseString(reader) var _2: Buffer? _2 = parseBytes(reader) + var _3: Buffer? + _3 = parseBytes(reader) + var _4: Int64? + _4 = reader.readInt64() let _c1 = _1 != nil let _c2 = _2 != nil - if _c1 && _c2 { - return Api.account.PasswordSettings.passwordSettings(email: _1!, secureSecret: _2!) - } - else { - return nil - } - } - - - } - - public enum AuthorizationResult { - case authorizationResult(userData: Api.DataJSON, acceptedFields: [Api.AuthFieldType]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .authorizationResult(let userData, let acceptedFields): - if boxed { - buffer.appendInt32(-2090391602) - } - userData.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(acceptedFields.count)) - for item in acceptedFields { - item.serialize(buffer, true) - } - break - } - } - fileprivate static func parse_authorizationResult(_ reader: BufferReader) -> AuthorizationResult? { - var _1: Api.DataJSON? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.DataJSON - } - var _2: [Api.AuthFieldType]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AuthFieldType.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.account.AuthorizationResult.authorizationResult(userData: _1!, acceptedFields: _2!) + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.account.PasswordSettings.passwordSettings(email: _1!, secureSalt: _2!, secureSecret: _3!, secureSecretHash: _4!) } else { return nil @@ -18773,20 +18910,22 @@ public struct Api { } public enum PasswordInputSettings { - case passwordInputSettings(flags: Int32, newSalt: Buffer?, newPasswordHash: Buffer?, hint: String?, email: String?, newSecureSecret: Buffer?) + case passwordInputSettings(flags: Int32, newSalt: Buffer?, newPasswordHash: Buffer?, hint: String?, email: String?, newSecureSalt: Buffer?, newSecureSecret: Buffer?, newSecureSecretHash: Int64?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .passwordInputSettings(let flags, let newSalt, let newPasswordHash, let hint, let email, let newSecureSecret): + case .passwordInputSettings(let flags, let newSalt, let newPasswordHash, let hint, let email, let newSecureSalt, let newSecureSecret, let newSecureSecretHash): if boxed { - buffer.appendInt32(550411865) + buffer.appendInt32(-447502641) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 0) != 0 {serializeBytes(newSalt!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeBytes(newPasswordHash!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(hint!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeString(email!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeBytes(newSecureSalt!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeBytes(newSecureSecret!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeInt64(newSecureSecretHash!, buffer: buffer, boxed: false)} break } } @@ -18803,14 +18942,20 @@ public struct Api { if Int(_1!) & Int(1 << 1) != 0 {_5 = parseString(reader) } var _6: Buffer? if Int(_1!) & Int(1 << 2) != 0 {_6 = parseBytes(reader) } + var _7: Buffer? + if Int(_1!) & Int(1 << 2) != 0 {_7 = parseBytes(reader) } + var _8: Int64? + if Int(_1!) & Int(1 << 2) != 0 {_8 = reader.readInt64() } let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.account.PasswordInputSettings.passwordInputSettings(flags: _1!, newSalt: _2, newPasswordHash: _3, hint: _4, email: _5, newSecureSecret: _6) + let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil + let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.account.PasswordInputSettings.passwordInputSettings(flags: _1!, newSalt: _2, newPasswordHash: _3, hint: _4, email: _5, newSecureSalt: _6, newSecureSecret: _7, newSecureSecretHash: _8) } else { return nil @@ -18896,65 +19041,26 @@ public struct Api { } - } - - public enum SecureValueResult { - case secureValueResultSaved - case secureValueVerificationNeeded(codeHash: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .secureValueResultSaved: - if boxed { - buffer.appendInt32(-186602735) - } - - break - case .secureValueVerificationNeeded(let codeHash): - if boxed { - buffer.appendInt32(-1852661285) - } - serializeString(codeHash, buffer: buffer, boxed: false) - break - } - } - fileprivate static func parse_secureValueResultSaved(_ reader: BufferReader) -> SecureValueResult? { - return Api.account.SecureValueResult.secureValueResultSaved - } - fileprivate static func parse_secureValueVerificationNeeded(_ reader: BufferReader) -> SecureValueResult? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.account.SecureValueResult.secureValueVerificationNeeded(codeHash: _1!) - } - else { - return nil - } - } - - } public enum AuthorizationForm { - case authorizationForm(flags: Int32, botId: Int32, fields: [Api.AuthField], acceptedFields: [Api.AuthFieldType], users: [Api.User]) + case authorizationForm(flags: Int32, requiredTypes: [Api.SecureValueType], values: [Api.SecureValue], users: [Api.User]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .authorizationForm(let flags, let botId, let fields, let acceptedFields, let users): + case .authorizationForm(let flags, let requiredTypes, let values, let users): if boxed { - buffer.appendInt32(1083800433) + buffer.appendInt32(-1919033877) } serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(botId, buffer: buffer, boxed: false) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(fields.count)) - for item in fields { + buffer.appendInt32(Int32(requiredTypes.count)) + for item in requiredTypes { item.serialize(buffer, true) } buffer.appendInt32(481674261) - buffer.appendInt32(Int32(acceptedFields.count)) - for item in acceptedFields { + buffer.appendInt32(Int32(values.count)) + for item in values { item.serialize(buffer, true) } buffer.appendInt32(481674261) @@ -18968,27 +19074,24 @@ public struct Api { fileprivate static func parse_authorizationForm(_ reader: BufferReader) -> AuthorizationForm? { var _1: Int32? _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: [Api.AuthField]? + var _2: [Api.SecureValueType]? if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AuthField.self) + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValueType.self) } - var _4: [Api.AuthFieldType]? + var _3: [Api.SecureValue]? if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AuthFieldType.self) + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SecureValue.self) } - var _5: [Api.User]? + var _4: [Api.User]? if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.account.AuthorizationForm.authorizationForm(flags: _1!, botId: _2!, fields: _3!, acceptedFields: _4!, users: _5!) + if _c1 && _c2 && _c3 && _c4 { + return Api.account.AuthorizationForm.authorizationForm(flags: _1!, requiredTypes: _2!, values: _3!, users: _4!) } else { return nil @@ -18999,26 +19102,28 @@ public struct Api { } public enum Password { - case noPassword(newSalt: Buffer, secretRandom: Buffer, emailUnconfirmedPattern: String) - case password(currentSalt: Buffer, newSalt: Buffer, secretRandom: Buffer, hint: String, hasRecovery: Api.Bool, emailUnconfirmedPattern: String) + case noPassword(newSalt: Buffer, newSecureSalt: Buffer, secureRandom: Buffer, emailUnconfirmedPattern: String) + case password(currentSalt: Buffer, newSalt: Buffer, newSecureSalt: Buffer, secureRandom: Buffer, hint: String, hasRecovery: Api.Bool, emailUnconfirmedPattern: String) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .noPassword(let newSalt, let secretRandom, let emailUnconfirmedPattern): + case .noPassword(let newSalt, let newSecureSalt, let secureRandom, let emailUnconfirmedPattern): if boxed { - buffer.appendInt32(-933006915) + buffer.appendInt32(1587643126) } serializeBytes(newSalt, buffer: buffer, boxed: false) - serializeBytes(secretRandom, buffer: buffer, boxed: false) + serializeBytes(newSecureSalt, buffer: buffer, boxed: false) + serializeBytes(secureRandom, buffer: buffer, boxed: false) serializeString(emailUnconfirmedPattern, buffer: buffer, boxed: false) break - case .password(let currentSalt, let newSalt, let secretRandom, let hint, let hasRecovery, let emailUnconfirmedPattern): + case .password(let currentSalt, let newSalt, let newSecureSalt, let secureRandom, let hint, let hasRecovery, let emailUnconfirmedPattern): if boxed { - buffer.appendInt32(1240452341) + buffer.appendInt32(-798203965) } serializeBytes(currentSalt, buffer: buffer, boxed: false) serializeBytes(newSalt, buffer: buffer, boxed: false) - serializeBytes(secretRandom, buffer: buffer, boxed: false) + serializeBytes(newSecureSalt, buffer: buffer, boxed: false) + serializeBytes(secureRandom, buffer: buffer, boxed: false) serializeString(hint, buffer: buffer, boxed: false) hasRecovery.serialize(buffer, true) serializeString(emailUnconfirmedPattern, buffer: buffer, boxed: false) @@ -19030,13 +19135,16 @@ public struct Api { _1 = parseBytes(reader) var _2: Buffer? _2 = parseBytes(reader) - var _3: String? - _3 = parseString(reader) + var _3: Buffer? + _3 = parseBytes(reader) + var _4: String? + _4 = parseString(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.account.Password.noPassword(newSalt: _1!, secretRandom: _2!, emailUnconfirmedPattern: _3!) + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.account.Password.noPassword(newSalt: _1!, newSecureSalt: _2!, secureRandom: _3!, emailUnconfirmedPattern: _4!) } else { return nil @@ -19049,22 +19157,25 @@ public struct Api { _2 = parseBytes(reader) var _3: Buffer? _3 = parseBytes(reader) - var _4: String? - _4 = parseString(reader) - var _5: Api.Bool? + var _4: Buffer? + _4 = parseBytes(reader) + var _5: String? + _5 = parseString(reader) + var _6: Api.Bool? if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.Bool + _6 = Api.parse(reader, signature: signature) as? Api.Bool } - var _6: String? - _6 = parseString(reader) + var _7: String? + _7 = parseString(reader) let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil let _c5 = _5 != nil let _c6 = _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.account.Password.password(currentSalt: _1!, newSalt: _2!, secretRandom: _3!, hint: _4!, hasRecovery: _5!, emailUnconfirmedPattern: _6!) + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.account.Password.password(currentSalt: _1!, newSalt: _2!, newSecureSalt: _3!, secureRandom: _4!, hint: _5!, hasRecovery: _6!, emailUnconfirmedPattern: _7!) } else { return nil @@ -22913,16 +23024,16 @@ public struct Api { }) } - public static func getSecureValue(userId: Api.InputUser, name: [String]) -> (CustomStringConvertible, Buffer, (Buffer) -> [Api.SecureValue]?) { + public static func getSecureValue(userId: Api.InputUser, types: [Api.SecureValueType]) -> (CustomStringConvertible, Buffer, (Buffer) -> [Api.SecureValue]?) { let buffer = Buffer() - buffer.appendInt32(-663771517) + buffer.appendInt32(-646023221) userId.serialize(buffer, true) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(name.count)) - for item in name { - serializeString(item, buffer: buffer, boxed: false) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) } - return (FunctionDescription({return "(account.getSecureValue userId: \(userId), name: \(name))"}), buffer, { (buffer: Buffer) -> [Api.SecureValue]? in + return (FunctionDescription({return "(account.getSecureValue userId: \(userId), types: \(types))"}), buffer, { (buffer: Buffer) -> [Api.SecureValue]? in let reader = BufferReader(buffer) var result: [Api.SecureValue]? if let _ = reader.readInt32() { @@ -22932,27 +23043,12 @@ public struct Api { }) } - public static func saveSecureValue(data: Api.InputSecureValue) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.account.SecureValueResult?) { + public static func saveSecureValue(value: Api.InputSecureValue, secureSecretHash: Int64) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.Bool?) { let buffer = Buffer() - buffer.appendInt32(-1614633436) - data.serialize(buffer, true) - return (FunctionDescription({return "(account.saveSecureValue data: \(data))"}), buffer, { (buffer: Buffer) -> Api.account.SecureValueResult? in - let reader = BufferReader(buffer) - var result: Api.account.SecureValueResult? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.account.SecureValueResult - } - return result - }) - } - - public static func verifySecureValue(name: String, codeHash: String, code: String) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.Bool?) { - let buffer = Buffer() - buffer.appendInt32(1748401133) - serializeString(name, buffer: buffer, boxed: false) - serializeString(codeHash, buffer: buffer, boxed: false) - serializeString(code, buffer: buffer, boxed: false) - return (FunctionDescription({return "(account.verifySecureValue name: \(name), codeHash: \(codeHash), code: \(code))"}), buffer, { (buffer: Buffer) -> Api.Bool? in + buffer.appendInt32(-1074098800) + value.serialize(buffer, true) + serializeInt64(secureSecretHash, buffer: buffer, boxed: false) + return (FunctionDescription({return "(account.saveSecureValue value: \(value), secureSecretHash: \(secureSecretHash))"}), buffer, { (buffer: Buffer) -> Api.Bool? in let reader = BufferReader(buffer) var result: Api.Bool? if let signature = reader.readInt32() { @@ -22962,21 +23058,31 @@ public struct Api { }) } - public static func getAuthorizationForm(flags: Int32, botId: Int32, scope: [String], origin: String?, packageName: String?, bundleId: String?, publicKey: String?) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.account.AuthorizationForm?) { + public static func deleteSecureValue(types: [Api.SecureValueType]) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.Bool?) { let buffer = Buffer() - buffer.appendInt32(788543543) - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(botId, buffer: buffer, boxed: false) + buffer.appendInt32(-1199522741) buffer.appendInt32(481674261) - buffer.appendInt32(Int32(scope.count)) - for item in scope { - serializeString(item, buffer: buffer, boxed: false) + buffer.appendInt32(Int32(types.count)) + for item in types { + item.serialize(buffer, true) } - if Int(flags) & Int(1 << 0) != 0 {serializeString(origin!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(packageName!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 2) != 0 {serializeString(bundleId!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(publicKey!, buffer: buffer, boxed: false)} - return (FunctionDescription({return "(account.getAuthorizationForm flags: \(flags), botId: \(botId), scope: \(scope), origin: \(String(describing: origin)), packageName: \(String(describing: packageName)), bundleId: \(String(describing: bundleId)), publicKey: \(String(describing: publicKey)))"}), buffer, { (buffer: Buffer) -> Api.account.AuthorizationForm? in + return (FunctionDescription({return "(account.deleteSecureValue types: \(types))"}), buffer, { (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 + }) + } + + public static func getAuthorizationForm(botId: Int32, scope: String, publicKey: String) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.account.AuthorizationForm?) { + let buffer = Buffer() + buffer.appendInt32(-1200903967) + serializeInt32(botId, buffer: buffer, boxed: false) + serializeString(scope, buffer: buffer, boxed: false) + serializeString(publicKey, buffer: buffer, boxed: false) + return (FunctionDescription({return "(account.getAuthorizationForm botId: \(botId), scope: \(scope), publicKey: \(publicKey))"}), buffer, { (buffer: Buffer) -> Api.account.AuthorizationForm? in let reader = BufferReader(buffer) var result: Api.account.AuthorizationForm? if let signature = reader.readInt32() { @@ -22986,35 +23092,23 @@ public struct Api { }) } - public static func acceptAuthorization(flags: Int32, botId: Int32, scope: [String], origin: String?, packageName: String?, bundleId: String?, publicKey: String?, acceptedFields: [Api.AuthFieldType], valueHashes: [Api.SecureValueHash]) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.account.AuthorizationResult?) { + public static func acceptAuthorization(botId: Int32, scope: String, publicKey: String, valueHashes: [Api.SecureValueHash], credentials: Api.SecureCredentialsEncrypted) -> (CustomStringConvertible, Buffer, (Buffer) -> Api.Bool?) { let buffer = Buffer() - buffer.appendInt32(1435792028) - serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(-419267436) serializeInt32(botId, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(scope.count)) - for item in scope { - serializeString(item, buffer: buffer, boxed: false) - } - if Int(flags) & Int(1 << 0) != 0 {serializeString(origin!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 1) != 0 {serializeString(packageName!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 2) != 0 {serializeString(bundleId!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(publicKey!, buffer: buffer, boxed: false)} - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(acceptedFields.count)) - for item in acceptedFields { - item.serialize(buffer, true) - } + serializeString(scope, buffer: buffer, boxed: false) + serializeString(publicKey, buffer: buffer, boxed: false) buffer.appendInt32(481674261) buffer.appendInt32(Int32(valueHashes.count)) for item in valueHashes { - item.serialize(buffer, false) + item.serialize(buffer, true) } - return (FunctionDescription({return "(account.acceptAuthorization flags: \(flags), botId: \(botId), scope: \(scope), origin: \(String(describing: origin)), packageName: \(String(describing: packageName)), bundleId: \(String(describing: bundleId)), publicKey: \(String(describing: publicKey)), acceptedFields: \(acceptedFields), valueHashes: \(valueHashes))"}), buffer, { (buffer: Buffer) -> Api.account.AuthorizationResult? in + credentials.serialize(buffer, true) + return (FunctionDescription({return "(account.acceptAuthorization botId: \(botId), scope: \(scope), publicKey: \(publicKey), valueHashes: \(valueHashes), credentials: \(credentials))"}), buffer, { (buffer: Buffer) -> Api.Bool? in let reader = BufferReader(buffer) - var result: Api.account.AuthorizationResult? + var result: Api.Bool? if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.account.AuthorizationResult + result = Api.parse(reader, signature: signature) as? Api.Bool } return result }) diff --git a/TelegramCore/Authorization.swift b/TelegramCore/Authorization.swift index a78f0003d4..ba1aed6d1f 100644 --- a/TelegramCore/Authorization.swift +++ b/TelegramCore/Authorization.swift @@ -156,7 +156,7 @@ public func authorizeWithCode(account: UnauthorizedAccount, code: String) -> Sig switch result { case .noPassword: return .fail(.generic) - case let .password(_, _, _, hint, _, _): + case let .password(_, _, _, _, hint, _, _): return .single(.password(hint: hint)) } } diff --git a/TelegramCore/RequestSecureIdForm.swift b/TelegramCore/RequestSecureIdForm.swift index 70385fe5f7..6343a196ec 100644 --- a/TelegramCore/RequestSecureIdForm.swift +++ b/TelegramCore/RequestSecureIdForm.swift @@ -13,139 +13,87 @@ public enum RequestSecureIdFormError { case generic } -public enum RequestedSecureIdField { - case identity - case address - case phone - case email -} - -private func parseRequestedFieldType(_ type: Api.AuthFieldType) -> RequestedSecureIdField { +private func parseSecureValueType(_ type: Api.SecureValueType) -> SecureIdRequestedFormField { switch type { - case .authFieldTypeIdentity: + case .secureValueTypeIdentity: return .identity - case .authFieldTypeAddress: + case .secureValueTypeAddress: return .address - case .authFieldTypePhone: + case .secureValueTypePhone: return .phone - case .authFieldTypeEmail: + case .secureValueTypeEmail: return .email } } -private func parseFileReference(_ file: Api.SecureFile) -> SecureIdFileReference { - switch file { - case .secureFileEmpty: - return .none - case let .secureFile(id, accessHash, size, dcId, fileHash): - return .file(id: id, accessHash: accessHash, size: size, datacenterId: dcId, fileHash: fileHash) +//secureData data:bytes data_hash:bytes = SecureData; + +private func parseSecureData(_ value: Api.SecureData) -> (data: Data, hash: Data) { + switch value { + case let .secureData(data, dataHash): + return (data.makeData(), dataHash.makeData()) } } -/*private func parseValue(_ value: Api.SecureValue) -> SecureIdFieldValue { +private func parseSecureValue(context: SecureIdAccessContext, value: Api.SecureValue) -> SecureIdValue? { switch value { - case let .secureValueEmpty(name): - return SecureIdFieldValue(name: name, data: .none) - case let .secureValueData(name, data, hash, secret): - return SecureIdFieldValue(name: name, data: .data(data: data.makeData(), hash: hash, secret: secret.makeData())) - case let .secureValueFile(name, file, hash, secret): - return SecureIdFieldValue(name: name, data: .files(files: file.map(parseFileReference), hash: hash, secret: secret.makeData())) - case let .secureValueText(name, text, hash): - return SecureIdFieldValue(name: name, data: .text(text: text, hash: hash)) - } -}*/ - -private func parseIdentityField(context: SecureIdAccessContext, value: Api.SecureValue, document: Api.SecureValue?) -> SecureIdIdentityField? { - switch value { - case let .secureValueData(name, data, hash, secret): - return nil - default: + case let .secureValueIdentity(_, data, files, secret, hash, verified): + let (encryptedData, encryptedHash) = parseSecureData(data) + guard let decryptedData = decryptedSecureData(context: context, data: encryptedData, dataHash: encryptedHash, encryptedSecret: secret.makeData()) else { + return nil + } + var fileReferences: [Int64: SecureIdFileReference] = [:] + for file in files.map(SecureIdFileReference.init).flatMap({ $0 }) { + fileReferences[file.id] = file + } + guard let value = SecureIdIdentityValue(data: decryptedData, fileReferences: fileReferences) else { + return nil + } + return .identity(value) + case let .secureValueAddress(_, data, files, secret, hash, verified): return nil + case let .secureValuePhone(_, phone, hash, verified): + guard let phoneData = phone.data(using: .utf8) else { + return nil + } + if sha256Digest(phoneData) != hash.makeData() { + return nil + } + return .phone(SecureIdPhoneValue(phone: phone)) + case let .secureValueEmail(_, email, hash, verified): + guard let emailData = email.data(using: .utf8) else { + return nil + } + if sha256Digest(emailData) != hash.makeData() { + return nil + } + return .email(SecureIdEmailValue(email: email)) } } -private func parsePhoneField(context: SecureIdAccessContext, value: Api.SecureValue) -> SecureIdPhoneField? { - switch value { - case let .secureValueText(name, text, _): - return SecureIdPhoneField(rawValue: text) - default: - return nil - } -} - -private func parseEmailField(context: SecureIdAccessContext, value: Api.SecureValue) -> SecureIdEmailField? { - switch value { - case let .secureValueText(name, text, _): - return SecureIdEmailField(rawValue: text) - default: - return nil - } -} - -private func parseFields(context: SecureIdAccessContext, fields: [Api.AuthField]) -> SecureIdFields { - var result = SecureIdFields(identity: nil, phone: nil, email: nil) - for field in fields { - switch field { - case let .authField(_, type, data, document): - switch type { - case .authFieldTypeIdentity: - if let identity = parseIdentityField(context: context, value: data, document: document) { - result.identity = .value(identity) - } else { - result.identity = .empty - } - case .authFieldTypeAddress: - break - case .authFieldTypePhone: - if let phone = parsePhoneField(context: context, value: data) { - result.phone = .value(phone) - } else { - result.phone = .empty - } - case .authFieldTypeEmail: - if let email = parseEmailField(context: context, value: data) { - result.email = .value(email) - } else { - result.email = .empty - } - } - } - } - return result +private func parseSecureValues(context: SecureIdAccessContext, values: [Api.SecureValue]) -> [SecureIdValue] { + return values.map({ parseSecureValue(context: context, value: $0) }).flatMap({ $0 }) } public struct EncryptedSecureIdForm { public let peerId: PeerId - public let requestedFields: [RequestedSecureIdField] + public let requestedFields: [SecureIdRequestedFormField] - let encryptedFields: [Api.AuthField] + let encryptedValues: [Api.SecureValue] } -public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: PeerId, scope: [String], origin: String?, packageName: String?, bundleId: String?, publicKey: String?) -> Signal { +public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: PeerId, scope: String, publicKey: String) -> Signal { if peerId.namespace != Namespaces.Peer.CloudUser { return .fail(.generic) } - var flags: Int32 = 0 - if let _ = origin { - flags |= 1 << 0 - } - if let _ = packageName { - flags |= 1 << 1 - } - if let _ = bundleId { - flags |= 1 << 2 - } - if let _ = publicKey { - flags |= 1 << 3 - } - return network.request(Api.functions.account.getAuthorizationForm(flags: flags, botId: peerId.id, scope: scope, origin: origin, packageName: packageName, bundleId: bundleId, publicKey: publicKey)) + return network.request(Api.functions.account.getAuthorizationForm(botId: peerId.id, scope: scope, publicKey: publicKey)) |> mapError { _ -> RequestSecureIdFormError in return .generic } |> mapToSignal { result -> Signal in return postbox.modify { modifier -> EncryptedSecureIdForm in switch result { - case let .authorizationForm(_, botId, fields, _, users): + case let .authorizationForm(_, requiredTypes, values, users): var peers: [Peer] = [] for user in users { let parsed = TelegramUser(user: user) @@ -155,17 +103,12 @@ public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: Peer return updated }) - return EncryptedSecureIdForm(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: botId), requestedFields: fields.map { field -> RequestedSecureIdField in - switch field { - case let .authField(_, type, data, document): - return parseRequestedFieldType(type) - } - }, encryptedFields: fields) + return EncryptedSecureIdForm(peerId: peerId, requestedFields: requiredTypes.map(parseSecureValueType), encryptedValues: values) } } |> mapError { _ in return RequestSecureIdFormError.generic } } } public func decryptedSecureIdForm(context: SecureIdAccessContext, form: EncryptedSecureIdForm) -> SecureIdForm? { - return SecureIdForm(peerId: form.peerId, fields: parseFields(context: context, fields: form.encryptedFields)) + return SecureIdForm(peerId: form.peerId, requestedFields: form.requestedFields, values: parseSecureValues(context: context, values: form.encryptedValues)) } diff --git a/TelegramCore/SaveSecureIdValue.swift b/TelegramCore/SaveSecureIdValue.swift new file mode 100644 index 0000000000..a53d40fd24 --- /dev/null +++ b/TelegramCore/SaveSecureIdValue.swift @@ -0,0 +1,150 @@ +import Foundation +#if os(macOS) + import PostboxMac + import MtProtoKitMac + import SwiftSignalKitMac +#else + import Postbox + import MtProtoKitDynamic + import SwiftSignalKit +#endif + +public enum SaveSecureIdValueError { + case generic +} + +private func paddedData(_ data: Data) -> Data { + var paddingCount = Int(47 + arc4random_uniform(255 - 47)) + paddingCount -= ((data.count + paddingCount) % 16) + var result = Data(count: paddingCount + data.count) + result.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + bytes.advanced(by: 0).pointee = UInt8(paddingCount) + arc4random_buf(bytes.advanced(by: 1), paddingCount - 1) + data.withUnsafeBytes { (source: UnsafePointer) -> Void in + memcpy(bytes.advanced(by: paddingCount), source, data.count) + } + } + return result +} + +private func unpaddedData(_ data: Data) -> Data? { + var paddingCount: UInt8 = 0 + data.copyBytes(to: &paddingCount, count: 1) + + if paddingCount < 0 || paddingCount > data.count { + return nil + } + + return data.subdata(in: Int(paddingCount) ..< data.count) +} + +struct EncryptedSecureData { + let data: Data + let hash: Data + let encryptedSecret: Data + let secretHash: Data +} + +func encryptedSecureData(context: SecureIdAccessContext, data: Data) -> EncryptedSecureData? { + let fileData = paddedData(data) + let fileHash = sha256Digest(fileData) + + guard let fileSecret = generateSecureSecretData() else { + return nil + } + let fileSecretHash = sha512Digest(fileSecret + fileHash) + let fileKey = fileSecretHash.subdata(in: 0 ..< 32) + let fileIv = fileSecretHash.subdata(in: 32 ..< (32 + 16)) + + guard let encryptedFileData = encryptSecureData(key: fileKey, iv: fileIv, data: fileData, decrypt: false) else { + return nil + } + + let secretHash = sha512Digest(context.secret) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + + guard let encryptedFileSecret = encryptSecureData(key: secretKey, iv: secretIv, data: fileSecret, decrypt: false) else { + return nil + } + + return EncryptedSecureData(data: encryptedFileData, hash: fileHash, encryptedSecret: encryptedFileSecret, secretHash: secretHash) +} + +func decryptedSecureData(context: SecureIdAccessContext, data: Data, dataHash: Data, encryptedSecret: Data) -> Data? { + let secretHash = sha512Digest(context.secret) + let secretKey = secretHash.subdata(in: 0 ..< 32) + let secretIv = secretHash.subdata(in: 32 ..< (32 + 16)) + + guard let fileSecret = encryptSecureData(key: secretKey, iv: secretIv, data: encryptedSecret, decrypt: true) else { + return nil + } + + if !verifySecureSecret(fileSecret) { + return nil + } + + let fileSecretHash = sha512Digest(fileSecret + dataHash) + let fileKey = fileSecretHash.subdata(in: 0 ..< 32) + let fileIv = fileSecretHash.subdata(in: 32 ..< (32 + 16)) + + guard let decryptedFileData = encryptSecureData(key: fileKey, iv: fileIv, data: data, decrypt: true) else { + return nil + } + + let checkDataHash = sha256Digest(decryptedFileData) + if checkDataHash != dataHash { + return nil + } + + return unpaddedData(decryptedFileData) +} + +private func makeInputSecureValue(context: SecureIdAccessContext, value: SecureIdValue) -> Api.InputSecureValue? { + switch value { + case .identity: + guard let (decryptedData, fileReferences) = value.serialize() else { + return nil + } + guard let encryptedData = encryptedSecureData(context: context, data: decryptedData) else { + return nil + } + + if let checkData = decryptedSecureData(context: context, data: encryptedData.data, dataHash: encryptedData.hash, encryptedSecret: encryptedData.encryptedSecret) { + if checkData != decryptedData { + return nil + } + } else { + return nil + } + + let files = fileReferences.map { file in + return Api.InputSecureFile.inputSecureFile(id: file.id, accessHash: file.accessHash) + } + + return Api.InputSecureValue.inputSecureValueIdentity(data: Api.SecureData.secureData(data: Buffer(data: encryptedData.data), dataHash: Buffer(data: encryptedData.hash)), files: files, secret: Buffer(data: encryptedData.encryptedSecret), hash: Buffer(data: encryptedData.secretHash)) + case let .phone(value): + guard let phoneData = value.phone.data(using: .utf8) else { + return nil + } + return Api.InputSecureValue.inputSecureValuePhone(phone: value.phone, hash: Buffer(data: sha256Digest(phoneData))) + case let .email(value): + guard let emailData = value.email.data(using: .utf8) else { + return nil + } + return Api.InputSecureValue.inputSecureValueEmail(email: value.email, hash: Buffer(data: sha256Digest(emailData))) + } +} + +public func saveSecureIdValue(network: Network, context: SecureIdAccessContext, value: SecureIdValue) -> Signal { + guard let inputValue = makeInputSecureValue(context: context, value: value) else { + return .fail(.generic) + } + return network.request(Api.functions.account.saveSecureValue(value: inputValue, secureSecretHash: context.hash)) + |> mapError { _ -> SaveSecureIdValueError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} diff --git a/TelegramCore/SecureIdDataTypes.swift b/TelegramCore/SecureIdDataTypes.swift index d9ef2f4d90..790df2c426 100644 --- a/TelegramCore/SecureIdDataTypes.swift +++ b/TelegramCore/SecureIdDataTypes.swift @@ -1,7 +1,7 @@ import Foundation public struct SecureIdDate: Equatable { - private var timestamp: Int32 + public let timestamp: Int32 public init(timestamp: Int32) { self.timestamp = timestamp @@ -20,24 +20,40 @@ public enum SecureIdGender { case female } -public enum SecureIdFileReference: Equatable { - case none - case file(id: Int64, accessHash: Int64, size: Int32, datacenterId: Int32, fileHash: String) +public struct SecureIdFileReference: Equatable { + let id: Int64 + let accessHash: Int64 + let size: Int32 + let datacenterId: Int32 + let fileHash: Data public static func ==(lhs: SecureIdFileReference, rhs: SecureIdFileReference) -> Bool { - switch lhs { - case .none: - if case .none = rhs { - return true - } else { - return false - } - case let .file(id, accessHash, size, datacenterId, fileHash): - if case .file(id, accessHash, size, datacenterId, fileHash) = rhs { - return true - } else { - return false - } + if lhs.id != rhs.id { + return false + } + if lhs.accessHash != rhs.accessHash { + return false + } + if lhs.size != rhs.size { + return false + } + if lhs.datacenterId != rhs.datacenterId { + return false + } + if lhs.fileHash != rhs.fileHash { + return false + } + return true + } +} + +extension SecureIdFileReference { + init?(apiFile: Api.SecureFile) { + switch apiFile { + case let .secureFile(id, accessHash, size, dcId, fileHash): + self.init(id: id, accessHash: accessHash, size: size, datacenterId: dcId, fileHash: fileHash.makeData()) + case .secureFileEmpty: + return nil } } } diff --git a/TelegramCore/SecureIdEmailField.swift b/TelegramCore/SecureIdEmailField.swift deleted file mode 100644 index 763f3be47b..0000000000 --- a/TelegramCore/SecureIdEmailField.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -public struct SecureIdEmailField: Equatable { - public let rawValue: String - - public init(rawValue: String) { - self.rawValue = rawValue - } - - public static func ==(lhs: SecureIdEmailField, rhs: SecureIdEmailField) -> Bool { - if lhs.rawValue != rhs.rawValue { - return false - } - return true - } -} diff --git a/TelegramCore/SecureIdEmailValue.swift b/TelegramCore/SecureIdEmailValue.swift new file mode 100644 index 0000000000..021a1b8fad --- /dev/null +++ b/TelegramCore/SecureIdEmailValue.swift @@ -0,0 +1,16 @@ +import Foundation + +public struct SecureIdEmailValue: Equatable { + public let email: String + + public init(email: String) { + self.email = email + } + + public static func ==(lhs: SecureIdEmailValue, rhs: SecureIdEmailValue) -> Bool { + if lhs.email != rhs.email { + return false + } + return true + } +} diff --git a/TelegramCore/SecureIdForm.swift b/TelegramCore/SecureIdForm.swift index 292c08e3cd..86a64f40d7 100644 --- a/TelegramCore/SecureIdForm.swift +++ b/TelegramCore/SecureIdForm.swift @@ -5,77 +5,72 @@ import Foundation import Postbox #endif -public enum SecureIdFieldValue: Equatable where T: Equatable { - case empty - case value(T) +public enum SecureIdValue: Equatable { + case identity(SecureIdIdentityValue) + case phone(SecureIdPhoneValue) + case email(SecureIdEmailValue) - public static func ==(lhs: SecureIdFieldValue, rhs: SecureIdFieldValue) -> Bool { + public static func ==(lhs: SecureIdValue, rhs: SecureIdValue) -> Bool { switch lhs { - case .empty: - if case .empty = rhs { + case let .identity(value): + if case .identity(value) = rhs { return true } else { return false } - case let .value(value): - if case .value(value) = rhs { + case let .phone(value): + if case .phone(value) = rhs { + return true + } else { + return false + } + case let .email(value): + if case .email(value) = rhs { return true } else { return false } } } + + func serialize() -> (Data, [SecureIdFileReference])? { + switch self { + case let .identity(value): + return value.serialize() + case .phone, .email: + return nil + } + } } -public struct SecureIdFields: Equatable { - public var identity: SecureIdFieldValue? - public var phone: SecureIdFieldValue? - public var email: SecureIdFieldValue? +public enum SecureIdRequestedFormField { + case identity + case address + case phone + case email +} + +public struct SecureIdForm: Equatable { + public let peerId: PeerId + public let requestedFields: [SecureIdRequestedFormField] + public let values: [SecureIdValue] - public static func ==(lhs: SecureIdFields, rhs: SecureIdFields) -> Bool { - if lhs.identity != rhs.identity { + public init(peerId: PeerId, requestedFields: [SecureIdRequestedFormField], values: [SecureIdValue]) { + self.peerId = peerId + self.requestedFields = requestedFields + self.values = values + } + + public static func ==(lhs: SecureIdForm, rhs: SecureIdForm) -> Bool { + if lhs.peerId != rhs.peerId { return false } - if lhs.phone != rhs.phone { + if lhs.requestedFields != rhs.requestedFields { return false } - if lhs.email != rhs.email { + if lhs.values != rhs.values { return false } return true } } - -public enum SecureIdField: Equatable { - case identity(SecureIdIdentityField) - case phone(SecureIdPhoneField) - case email(SecureIdEmailField) - - public static func ==(lhs: SecureIdField, rhs: SecureIdField) -> Bool { - switch lhs { - case let .identity(field): - if case .identity(field) = rhs { - return true - } else { - return false - } - case let .phone(field): - if case .phone(field) = rhs { - return true - } else { - return false - } - case let .email(field): - if case .email(field) = rhs { - return true - } else { - return false - } - } - } -} - -public struct SecureIdForm { - public let peerId: PeerId - public let fields: SecureIdFields -} diff --git a/TelegramCore/SecureIdIdentityField.swift b/TelegramCore/SecureIdIdentityField.swift deleted file mode 100644 index d67802a7a2..0000000000 --- a/TelegramCore/SecureIdIdentityField.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -public struct SecureIdIdentityField: Equatable { - public var passport: SecureIdPassportIdentity? - - public init(passport: SecureIdPassportIdentity?) { - self.passport = passport - } - - public static func ==(lhs: SecureIdIdentityField, rhs: SecureIdIdentityField) -> Bool { - if lhs.passport != rhs.passport { - return false - } - return true - } -} diff --git a/TelegramCore/SecureIdIdentityValue.swift b/TelegramCore/SecureIdIdentityValue.swift new file mode 100644 index 0000000000..93c85d074f --- /dev/null +++ b/TelegramCore/SecureIdIdentityValue.swift @@ -0,0 +1,227 @@ +import Foundation + +public enum SecureIdIdentityValue: Equatable { + case passport(SecureIdIdentityPassportValue) + + public static func ==(lhs: SecureIdIdentityValue, rhs: SecureIdIdentityValue) -> Bool { + switch lhs { + case let .passport(value): + if case .passport(value) = rhs { + return true + } else { + return false + } + } + } +} + +public struct SecureIdIdentityPassportValue: Equatable { + public var identifier: String + public var firstName: String + public var lastName: String + public var birthdate: SecureIdDate + public var countryCode: String + public var gender: SecureIdGender + public var issueDate: SecureIdDate + public var expiryDate: SecureIdDate? + public var verificationDocuments: [SecureIdFileReference] + + public init(identifier: String, firstName: String, lastName: String, birthdate: SecureIdDate, countryCode: String, gender: SecureIdGender, issueDate: SecureIdDate, expiryDate: SecureIdDate?, verificationDocuments: [SecureIdFileReference]) { + self.identifier = identifier + self.firstName = firstName + self.lastName = lastName + self.birthdate = birthdate + self.countryCode = countryCode + self.gender = gender + self.issueDate = issueDate + self.expiryDate = expiryDate + self.verificationDocuments = verificationDocuments + } + + public static func ==(lhs: SecureIdIdentityPassportValue, rhs: SecureIdIdentityPassportValue) -> Bool { + if lhs.identifier != rhs.identifier { + return false + } + if lhs.firstName != rhs.firstName { + return false + } + if lhs.lastName != rhs.lastName { + return false + } + if lhs.birthdate != rhs.birthdate { + return false + } + if lhs.countryCode != rhs.countryCode { + return false + } + if lhs.gender != rhs.gender { + return false + } + if lhs.issueDate != rhs.issueDate { + return false + } + if lhs.expiryDate != rhs.expiryDate { + return false + } + return true + } +} + +private func parseGender(_ string: String) -> SecureIdGender? { + switch string { + case "male": + return .male + case "female": + return .female + default: + return nil + } +} + +private func serializeGender(_ gender: SecureIdGender) -> String { + switch gender { + case .male: + return "male" + case .female: + return "female" + } +} + +private let dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "dd.MM.yyyy" + formatter.timeZone = TimeZone(secondsFromGMT: 0) + formatter.locale = Locale(identifier: "en_US_POSIX") + return formatter +}() + +private func parseDate(_ string: String) -> SecureIdDate? { + guard let date = dateFormatter.date(from: string) else { + return nil + } + return SecureIdDate(timestamp: Int32(date.timeIntervalSince1970)) +} + +private func serializeDate(_ date: SecureIdDate) -> String { + return dateFormatter.string(from: Date(timeIntervalSince1970: Double(date.timestamp))) +} + +private func parseFileReferenceId(_ string: String) -> Int64? { + let data = dataWithHexString(string) + if data.count != 8 { + return nil + } + var value: Int64 = 0 + data.withUnsafeBytes { (bytes: UnsafePointer) -> Void in + memcpy(&value, bytes, 8) + } + return value +} + +private func serializeFileReferenceId(_ id: Int64) -> String { + var data = Data(count: 8) + data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in + var id = id + memcpy(bytes, &id, 8) + } + return hexString(data) +} + +extension SecureIdIdentityValue { + init?(data: Data, fileReferences: [Int64: SecureIdFileReference]) { + guard let dict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else { + return nil + } + guard let documentType = dict["document_type"] as? String else { + return nil + } + + switch documentType { + case "passport": + if let passport = SecureIdIdentityPassportValue(dict: dict, fileReferences: fileReferences) { + self = .passport(passport) + } + default: + return nil + } + + return nil + } + + func serialize() -> (Data, [SecureIdFileReference])? { + var dict: [String: Any] = [:] + let fileReferences: [SecureIdFileReference] + switch self { + case let .passport(value): + dict["document_type"] = "passport" + let (valueDict, references) = value.serialize() + dict.merge(valueDict, uniquingKeysWith: { lhs, _ in return lhs }) + fileReferences = references + } + guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else { + return nil + } + return (data, fileReferences) + } +} + +private extension SecureIdIdentityPassportValue { + init?(dict: [String: Any], fileReferences: [Int64: SecureIdFileReference]) { + guard let identifier = dict["document_no"] as? String else { + return nil + } + guard let firstName = dict["first_name"] as? String else { + return nil + } + guard let lastName = dict["last_name"] as? String else { + return nil + } + guard let birthdate = (dict["date_of_birth"] as? String).flatMap(parseDate) else { + return nil + } + guard let gender = (dict["gender"] as? String).flatMap(parseGender) else { + return nil + } + guard let countryCode = dict["country_code"] as? String else { + return nil + } + guard let issueDate = (dict["issue_date"] as? String).flatMap(parseDate) else { + return nil + } + let expiryDate = (dict["expiry_date"] as? String).flatMap(parseDate) + + var verificationDocuments: [SecureIdFileReference] = [] + if let files = dict["files"] as? [String] { + for fileId in files { + guard let fileId = parseFileReferenceId(fileId) else { + continue + } + guard let file = fileReferences[fileId] else { + continue + } + verificationDocuments.append(file) + } + } + + self.init(identifier: identifier, firstName: firstName, lastName: lastName, birthdate: birthdate, countryCode: countryCode, gender: gender, issueDate: issueDate, expiryDate: expiryDate, verificationDocuments: verificationDocuments) + } + + func serialize() -> ([String: Any], [SecureIdFileReference]) { + var dict: [String: Any] = [:] + dict["document_no"] = self.identifier + dict["first_name"] = self.firstName + dict["last_name"] = self.lastName + dict["date_of_birth"] = serializeDate(self.birthdate) + dict["gender"] = serializeGender(self.gender) + dict["country_code"] = self.countryCode + dict["issue_date"] = serializeDate(self.issueDate) + if let expiryDate = self.expiryDate { + dict["expiry_date"] = serializeDate(expiryDate) + } + if !self.verificationDocuments.isEmpty { + dict["files"] = self.verificationDocuments.map { serializeFileReferenceId($0.id) } + } + + return (dict, self.verificationDocuments) + } +} diff --git a/TelegramCore/SecureIdPassportIdentity.swift b/TelegramCore/SecureIdPassportIdentity.swift deleted file mode 100644 index 1d3a4039f1..0000000000 --- a/TelegramCore/SecureIdPassportIdentity.swift +++ /dev/null @@ -1,41 +0,0 @@ -import Foundation - -public struct SecureIdPassportIdentity: Equatable { - public var id: String - public var firstName: String - public var lastName: String - public var birthdate: SecureIdDate - public var countryCode: String - public var gender: SecureIdGender - - public init(id: String, firstName: String, lastName: String, birthdate: SecureIdDate, countryCode: String, gender: SecureIdGender) { - self.id = id - self.firstName = firstName - self.lastName = lastName - self.birthdate = birthdate - self.countryCode = countryCode - self.gender = gender - } - - public static func ==(lhs: SecureIdPassportIdentity, rhs: SecureIdPassportIdentity) -> Bool { - if lhs.id != rhs.id { - return false - } - if lhs.firstName != rhs.firstName { - return false - } - if lhs.lastName != rhs.lastName { - return false - } - if lhs.birthdate != rhs.birthdate { - return false - } - if lhs.countryCode != rhs.countryCode { - return false - } - if lhs.gender != rhs.gender { - return false - } - return true - } -} diff --git a/TelegramCore/SecureIdPhoneField.swift b/TelegramCore/SecureIdPhoneField.swift deleted file mode 100644 index 3d7161ada7..0000000000 --- a/TelegramCore/SecureIdPhoneField.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -public struct SecureIdPhoneField: Equatable { - public let rawValue: String - - public init(rawValue: String) { - self.rawValue = rawValue - } - - public static func ==(lhs: SecureIdPhoneField, rhs: SecureIdPhoneField) -> Bool { - if lhs.rawValue != rhs.rawValue { - return false - } - return true - } -} diff --git a/TelegramCore/SecureIdPhoneValue.swift b/TelegramCore/SecureIdPhoneValue.swift new file mode 100644 index 0000000000..e45f4fa631 --- /dev/null +++ b/TelegramCore/SecureIdPhoneValue.swift @@ -0,0 +1,16 @@ +import Foundation + +public struct SecureIdPhoneValue: Equatable { + public let phone: String + + public init(phone: String) { + self.phone = phone + } + + public static func ==(lhs: SecureIdPhoneValue, rhs: SecureIdPhoneValue) -> Bool { + if lhs.phone != rhs.phone { + return false + } + return true + } +} diff --git a/TelegramCore/TwoStepVerification.swift b/TelegramCore/TwoStepVerification.swift index b430c12baa..41d69355cd 100644 --- a/TelegramCore/TwoStepVerification.swift +++ b/TelegramCore/TwoStepVerification.swift @@ -19,22 +19,37 @@ public func twoStepVerificationConfiguration(account: Account) -> Signal retryRequest |> map { result -> TwoStepVerificationConfiguration in switch result { - case let .noPassword(_, _, emailUnconfirmedPattern): + case let .noPassword(_, _, _, emailUnconfirmedPattern): return .notSet(pendingEmailPattern: emailUnconfirmedPattern) - case let .password(_, _, _, hint, hasRecovery, emailUnconfirmedPattern): + case let .password(_, _, _, _, hint, hasRecovery, emailUnconfirmedPattern): return .set(hint: hint, hasRecoveryEmail: hasRecovery == .boolTrue, pendingEmailPattern: emailUnconfirmedPattern) } } } +public struct TwoStepVerificationSecureSecret { + public let data: Data + public let salt: Data + public let hash: Int64 +} + public struct TwoStepVerificationSettings { public let email: String - public let secureSecret: Data? + public let secureSecret: TwoStepVerificationSecureSecret? } public func requestTwoStepVerifiationSettings(network: Network, password: String) -> Signal { return twoStepAuthData(network) - |> mapToSignal { authData -> Signal in + |> mapError { error -> AuthorizationPasswordVerificationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "PASSWORD_HASH_INVALID" { + return .invalidPassword + } else { + return .generic + } + } + |> mapToSignal { authData -> Signal in var data = Data() data.append(authData.currentSalt!) data.append(password.data(using: .utf8, allowLossyConversion: true)!) @@ -42,22 +57,23 @@ public func requestTwoStepVerifiationSettings(network: Network, password: String let currentPasswordHash = sha256Digest(data) return network.request(Api.functions.account.getPasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false) - |> map { result -> TwoStepVerificationSettings in + |> mapError { _ -> AuthorizationPasswordVerificationError in + return .generic + } + |> mapToSignal { result -> Signal in switch result { - case let .passwordSettings(email, secureSecret): - return TwoStepVerificationSettings(email: email, secureSecret: secureSecret.size == 0 ? nil : secureSecret.makeData()) + case let .passwordSettings(email, secureSalt, secureSecret, secureSecretHash): + var parsedSecureSecret: TwoStepVerificationSecureSecret? + if secureSalt.size != 0 && secureSecret.size != 0 { + if secureSecret.size != 32 { + return .fail(.generic) + } + parsedSecureSecret = TwoStepVerificationSecureSecret(data: secureSecret.makeData(), salt: secureSalt.makeData(), hash: secureSecretHash) + } + return .single(TwoStepVerificationSettings(email: email, secureSecret: parsedSecureSecret)) } } } - |> `catch` { error -> Signal in - if error.errorDescription.hasPrefix("FLOOD_WAIT") { - return .fail(.limitExceeded) - } else if error.errorDescription == "PASSWORD_HASH_INVALID" { - return .fail(.invalidPassword) - } else { - return .fail(.generic) - } - } } public enum UpdateTwoStepVerificationPasswordError { @@ -80,7 +96,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: |> mapError { _ -> UpdateTwoStepVerificationPasswordError in return .generic } - |> mapToSignal { authData -> Signal<(TwoStepAuthData, Data?), UpdateTwoStepVerificationPasswordError> in + |> mapToSignal { authData -> Signal<(TwoStepAuthData, TwoStepVerificationSecureSecret?), UpdateTwoStepVerificationPasswordError> in if authData.currentSalt != nil { return requestTwoStepVerifiationSettings(network: network, password: currentPassword ?? "") |> mapError { _ -> UpdateTwoStepVerificationPasswordError in @@ -114,7 +130,7 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: flags |= (1 << 0) } - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: .passwordInputSettings(flags: flags, newSalt: Buffer(data: Data()), newPasswordHash: Buffer(data: Data()), hint: "", email: "", newSecureSecret: nil)), automaticFloodWait: false) + return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: .passwordInputSettings(flags: flags, newSalt: Buffer(data: Data()), newPasswordHash: Buffer(data: Data()), hint: "", email: "", newSecureSalt: nil, newSecureSecret: nil, newSecureSecretHash: nil)), automaticFloodWait: false) |> mapError { _ -> UpdateTwoStepVerificationPasswordError in return .generic } @@ -140,18 +156,22 @@ public func updateTwoStepVerificationPassword(network: Network, currentPassword: updatedData.append(password.data(using: .utf8, allowLossyConversion: true)!) updatedData.append(nextSalt) - var updatedSecureSecret: Data? + var updatedSecureSecret: TwoStepVerificationSecureSecret? if let encryptedSecret = secureSecret { flags |= 1 << 2 - if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: currentPassword ?? "") { - updatedSecureSecret = encryptedSecureSecret(secretData: decryptedSecret, password: password) + if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: encryptedSecret.data, password: currentPassword ?? "", salt: encryptedSecret.salt, hash: encryptedSecret.hash) { + if let (data, salt, hash) = encryptedSecureSecret(secretData: decryptedSecret, password: password, inputSalt: authData.nextSecureSalt) { + updatedSecureSecret = TwoStepVerificationSecureSecret(data: data, salt: salt, hash: hash) + } else { + return .fail(.generic) + } } else { - updatedSecureSecret = Data() + return .fail(.generic) } } let updatedPasswordHash = sha256Digest(updatedData) - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newSalt: Buffer(data: nextSalt), newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSecret: updatedSecureSecret.flatMap(Buffer.init))), automaticFloodWait: false) + return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newSalt: Buffer(data: nextSalt), newPasswordHash: Buffer(data: updatedPasswordHash), hint: hint, email: email, newSecureSalt: (updatedSecureSecret?.salt).flatMap(Buffer.init), newSecureSecret: (updatedSecureSecret?.data).flatMap(Buffer.init), newSecureSecretHash: updatedSecureSecret?.hash)), automaticFloodWait: false) |> map { _ -> UpdateTwoStepVerificationPasswordResult in return .password(password: password, pendingEmailPattern: nil) } @@ -184,7 +204,7 @@ enum UpdateTwoStepVerificationSecureSecretError { case generic } -func updateTwoStepVerificationSecureSecret(network: Network, password: String, updatedSecret: Data) -> Signal { +func updateTwoStepVerificationSecureSecret(network: Network, password: String, secret: Data) -> Signal { return twoStepAuthData(network) |> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in return .generic @@ -194,14 +214,22 @@ func updateTwoStepVerificationSecureSecret(network: Network, password: String, u return .fail(.generic) } + guard let passwordData = password.data(using: .utf8) else { + return .fail(.generic) + } + var data = Data() data.append(currentSalt) - data.append(password.data(using: .utf8, allowLossyConversion: true)!) + data.append(passwordData) data.append(currentSalt) let currentPasswordHash = Buffer(data: sha256Digest(data)) + guard let (encryptedSecret, secretSalt, secretHash) = encryptedSecureSecret(secretData: secret, password: password, inputSalt: authData.nextSecureSalt) else { + return .fail(.generic) + } + let flags: Int32 = (1 << 2) - return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: .passwordInputSettings(flags: flags, newSalt: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSecret: Buffer(data: updatedSecret))), automaticFloodWait: false) + return network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: .passwordInputSettings(flags: flags, newSalt: nil, newPasswordHash: nil, hint: nil, email: nil, newSecureSalt: Buffer(data: secretSalt), newSecureSecret: Buffer(data: encryptedSecret), newSecureSecretHash: secretHash)), automaticFloodWait: false) |> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in return .generic } @@ -229,7 +257,7 @@ public func updateTwoStepVerificationEmail(account: Account, currentPassword: St } let flags: Int32 = 1 << 1 - return account.network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newSalt: nil, newPasswordHash: nil, hint: nil, email: updatedEmail, newSecureSecret: nil)), automaticFloodWait: false) + return account.network.request(Api.functions.account.updatePasswordSettings(currentPasswordHash: currentPasswordHash, newSettings: Api.account.PasswordInputSettings.passwordInputSettings(flags: flags, newSalt: nil, newPasswordHash: nil, hint: nil, email: updatedEmail, newSecureSalt: nil, newSecureSecret: nil, newSecureSecretHash: nil)), automaticFloodWait: false) |> map { _ -> UpdateTwoStepVerificationPasswordResult in return .password(password: currentPassword, pendingEmailPattern: nil) }