no message

This commit is contained in:
Peter Iakovlev
2018-03-23 03:11:22 +04:00
parent bd1ab209ab
commit d67854a097
11 changed files with 624 additions and 55 deletions

View File

@@ -362,6 +362,16 @@
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 */; };
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 */; };
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 */; };
@@ -499,6 +509,8 @@
D0BE303B20619EE800FBE6D8 /* SecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */; };
D0BE303D2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */; };
D0BE303E2061A29100FBE6D8 /* RequestSecureIdForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */; };
D0BE304B20627D9800FBE6D8 /* AccessSecureId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */; };
D0BE304C20627D9800FBE6D8 /* AccessSecureId.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */; };
D0BE383E1E7C5995000079AF /* MediaPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE383D1E7C5995000079AF /* MediaPool.swift */; };
D0BE383F1E7C5995000079AF /* MediaPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE383D1E7C5995000079AF /* MediaPool.swift */; };
D0BEAF5D1E54941B00BD963D /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF5C1E54941B00BD963D /* Authorization.swift */; };
@@ -840,6 +852,11 @@
D08CAA8B1ED81EDF0000FDA8 /* Localizations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Localizations.swift; sourceTree = "<group>"; };
D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = "<group>"; };
D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = "<group>"; };
D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPassportIdentity.swift; sourceTree = "<group>"; };
D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdDataTypes.swift; sourceTree = "<group>"; };
D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdIdentityField.swift; sourceTree = "<group>"; };
D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdPhoneField.swift; sourceTree = "<group>"; };
D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdEmailField.swift; sourceTree = "<group>"; };
D099D7451EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelMessageStateVersionAttribute.swift; sourceTree = "<group>"; };
D099D7481EEF418D00A3128C /* HistoryViewChannelStateValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryViewChannelStateValidation.swift; sourceTree = "<group>"; };
D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = "<group>"; };
@@ -922,6 +939,7 @@
D0BC387A1E40D2880044D6FE /* TogglePeerChatPinned.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TogglePeerChatPinned.swift; sourceTree = "<group>"; };
D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureIdForm.swift; sourceTree = "<group>"; };
D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestSecureIdForm.swift; sourceTree = "<group>"; };
D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessSecureId.swift; sourceTree = "<group>"; };
D0BE383D1E7C5995000079AF /* MediaPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaPool.swift; sourceTree = "<group>"; };
D0BEAF5C1E54941B00BD963D /* Authorization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = "<group>"; };
D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
@@ -1479,6 +1497,42 @@
name = Localization;
sourceTree = "<group>";
};
D093D7E82064135300BC3599 /* Fields */ = {
isa = PBXGroup;
children = (
D093D7ED206413F600BC3599 /* SecureIdDataTypes.swift */,
D093D7E92064135A00BC3599 /* Identity */,
D093D7F320641A3F00BC3599 /* Phone */,
D093D7F720641A9600BC3599 /* Email */,
);
name = Fields;
sourceTree = "<group>";
};
D093D7E92064135A00BC3599 /* Identity */ = {
isa = PBXGroup;
children = (
D093D7F02064194600BC3599 /* SecureIdIdentityField.swift */,
D093D7EA206413C900BC3599 /* SecureIdPassportIdentity.swift */,
);
name = Identity;
sourceTree = "<group>";
};
D093D7F320641A3F00BC3599 /* Phone */ = {
isa = PBXGroup;
children = (
D093D7F420641A4900BC3599 /* SecureIdPhoneField.swift */,
);
name = Phone;
sourceTree = "<group>";
};
D093D7F720641A9600BC3599 /* Email */ = {
isa = PBXGroup;
children = (
D093D7F820641AA500BC3599 /* SecureIdEmailField.swift */,
);
name = Email;
sourceTree = "<group>";
};
D09D8BF71D4FAB1D0081DBEC = {
isa = PBXGroup;
children = (
@@ -1569,6 +1623,8 @@
children = (
D0BE303920619EE800FBE6D8 /* SecureIdForm.swift */,
D0BE303C2061A29100FBE6D8 /* RequestSecureIdForm.swift */,
D0BE304A20627D9800FBE6D8 /* AccessSecureId.swift */,
D093D7E82064135300BC3599 /* Fields */,
);
name = "Secure ID";
sourceTree = "<group>";
@@ -1848,6 +1904,7 @@
D021E0DF1DB539FC00C6B04F /* StickerPack.swift in Sources */,
D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */,
D0DFD5DF1FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */,
D093D7EE206413F600BC3599 /* SecureIdDataTypes.swift in Sources */,
D00D343C1E6EC9770057B307 /* TelegramMediaGame.swift in Sources */,
D033FEB01E61EB0200644997 /* PeerReportStatus.swift in Sources */,
D050F2511E4A59C200988324 /* JoinLink.swift in Sources */,
@@ -1895,6 +1952,7 @@
D0DF0CA81D82BF32008AEB01 /* PeerParticipants.swift in Sources */,
D0FA8BA71E1FA6DF001E855B /* TelegramSecretChat.swift in Sources */,
D03B0D5F1D631A6900955575 /* Serialization.swift in Sources */,
D093D7F920641AA500BC3599 /* SecureIdEmailField.swift in Sources */,
D0C44B611FC616E200227BE0 /* SearchGroupMembers.swift in Sources */,
D03B0D441D6319F900955575 /* CloudFileMediaResource.swift in Sources */,
D018D3371E648ACF00C5E089 /* CreateChannel.swift in Sources */,
@@ -1988,6 +2046,7 @@
D0F7AB2C1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */,
D0FA8BAA1E1FB76E001E855B /* ManagedSecretChatOutgoingOperations.swift in Sources */,
D00D97C71E32901700E5C2B6 /* PeerInputActivity.swift in Sources */,
D093D7EB206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */,
D0FA8BAD1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */,
D03B0CBF1D62234A00955575 /* Log.swift in Sources */,
C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */,
@@ -2023,6 +2082,7 @@
D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */,
D00C7CCC1E3620C30080C3D5 /* CachedChannelParticipants.swift in Sources */,
D09BB6B41DB02C2B00A905C0 /* PendingMessageManager.swift in Sources */,
D093D7F520641A4900BC3599 /* SecureIdPhoneField.swift in Sources */,
D0B167231F9F972E00976B40 /* LoggingSettings.swift in Sources */,
D0BC387B1E40D2880044D6FE /* TogglePeerChatPinned.swift in Sources */,
D0BB7C5A1E5C8074001527C3 /* ChannelParticipants.swift in Sources */,
@@ -2038,6 +2098,7 @@
D01C7ED31EF5DF83008305F1 /* LimitsConfiguration.swift in Sources */,
D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */,
D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */,
D0BE304B20627D9800FBE6D8 /* AccessSecureId.swift in Sources */,
D0BEAF5D1E54941B00BD963D /* Authorization.swift in Sources */,
D0C26D6C1FE286C3004ABF18 /* FetchChatList.swift in Sources */,
D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */,
@@ -2095,6 +2156,7 @@
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 */,
@@ -2161,6 +2223,7 @@
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 */,
@@ -2252,6 +2315,7 @@
D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */,
D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */,
D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */,
D093D7EF206413F600BC3599 /* SecureIdDataTypes.swift in Sources */,
D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */,
D0C44B621FC616E200227BE0 /* SearchGroupMembers.swift in Sources */,
D00C7CD01E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */,
@@ -2280,8 +2344,10 @@
D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */,
D07047B51F3DF1FE00F6A8D4 /* ConsumablePersonalMentionMessageAttribute.swift in Sources */,
D0448C8F1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */,
D093D7F620641A4900BC3599 /* SecureIdPhoneField.swift in Sources */,
D0C26D6D1FE286C3004ABF18 /* FetchChatList.swift in Sources */,
D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */,
D093D7FA20641AA500BC3599 /* SecureIdEmailField.swift in Sources */,
D05A32E21E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */,
D0613FD01E60520700202CDB /* ChannelMembers.swift in Sources */,
D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */,
@@ -2302,6 +2368,7 @@
D0B418A91D7E0597004562A4 /* Buffer.swift in Sources */,
D02ABC821E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift in Sources */,
C2FD33E51E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */,
D0BE304C20627D9800FBE6D8 /* AccessSecureId.swift in Sources */,
D0B8442E1DAB91E0005F29E1 /* NBMetadataCoreTestMapper.m in Sources */,
D01A21AD1F38D10E00DDA104 /* SavedStickerItem.swift in Sources */,
D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */,
@@ -2396,6 +2463,7 @@
D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */,
D058E0D21E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */,
D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */,
D093D7EC206413C900BC3599 /* SecureIdPassportIdentity.swift in Sources */,
D0FA8BBA1E2240B4001E855B /* SecretChatIncomingDecryptedOperation.swift in Sources */,
D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */,
D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */,

View File

@@ -0,0 +1,185 @@
import Foundation
#if os(macOS)
import PostboxMac
import MtProtoKitMac
import SwiftSignalKitMac
#else
import Postbox
import MtProtoKitDynamic
import SwiftSignalKit
#endif
import TelegramCorePrivateModule
private enum GenerateSecureSecretError {
case generic
}
func decryptedSecureSecret(encryptedSecretData: Data, password: String) -> Data? {
guard let passwordData = password.data(using: .utf8) else {
return nil
}
let passwordHash = sha512Digest(passwordData)
let secretKey = passwordHash.subdata(in: 0 ..< 32)
let iv = passwordHash.subdata(in: 32 ..< (32 + 16))
var decryptedSecret = Data(count: encryptedSecretData.count)
guard decryptedSecret.withUnsafeMutableBytes({ (decryptedSecretBytes: UnsafeMutablePointer<Int8>) -> Bool in
return secretKey.withUnsafeBytes { (secretKeyBytes: UnsafePointer<Int8>) -> Bool in
return iv.withUnsafeBytes { (ivBytes: UnsafePointer<Int8>) -> Bool in
return encryptedSecretData.withUnsafeBytes { (encryptedSecretDataBytes: UnsafePointer<Int8>) -> Bool in
var processedCount: Int = 0
let result = CCCrypt(CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithmAES128), 0, secretKeyBytes, secretKey.count, ivBytes, encryptedSecretDataBytes, encryptedSecretData.count, decryptedSecretBytes, decryptedSecret.count, &processedCount)
if result != kCCSuccess {
return false
}
if processedCount != decryptedSecret.count {
return false
}
return true
}
}
}
}) else {
return nil
}
guard decryptedSecret.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> 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 {
return nil
}
return decryptedSecret
}
func encryptedSecureSecret(secretData: Data, password: String) -> Data? {
guard let passwordData = password.data(using: .utf8) else {
return nil
}
let passwordHash = sha512Digest(passwordData)
let secretKey = passwordHash.subdata(in: 0 ..< 32)
let iv = passwordHash.subdata(in: 32 ..< (32 + 16))
var encryptedSecret = Data(count: secretData.count)
guard encryptedSecret.withUnsafeMutableBytes({ (encryptedSecretBytes: UnsafeMutablePointer<Int8>) -> Bool in
return secretKey.withUnsafeBytes { (secretKeyBytes: UnsafePointer<Int8>) -> Bool in
return iv.withUnsafeBytes { (ivBytes: UnsafePointer<Int8>) -> Bool in
return secretData.withUnsafeBytes { (secretDataBytes: UnsafePointer<Int8>) -> Bool in
var processedCount: Int = 0
let result = CCCrypt(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128), 0, secretKeyBytes, secretKey.count, ivBytes, secretDataBytes, secretData.count, encryptedSecretBytes, encryptedSecret.count, &processedCount)
if result != kCCSuccess {
return false
}
if processedCount != encryptedSecret.count {
return false
}
return true
}
}
}
}) else {
return nil
}
if decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: password) != secretData {
return nil
}
return encryptedSecret
}
private func generateSecureSecret(network: Network, password: String) -> Signal<Data, GenerateSecureSecretError> {
var secretData = Data(count: 32)
guard secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<Int8>) -> Bool in
let copyResult = SecRandomCopyBytes(nil, 32, bytes)
return copyResult == errSecSuccess
}) else {
return .fail(.generic)
}
secretData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) in
while true {
var checksum: UInt32 = 0
for i in 0 ..< secretData.count {
checksum += UInt32(bytes.advanced(by: i).pointee)
checksum = checksum % 255
}
if checksum == 239 {
break
} else {
var i = secretData.count - 1
inner: while i >= 0 {
var byte = bytes.advanced(by: i).pointee
if byte != 0xff {
byte += 1
bytes.advanced(by: i).pointee = byte
break inner
} else {
byte = 0
bytes.advanced(by: i).pointee = byte
}
i -= 1
}
}
}
})
guard let encryptedSecret = encryptedSecureSecret(secretData: secretData, password: password) else {
return .fail(.generic)
}
return updateTwoStepVerificationSecureSecret(network: network, password: password, updatedSecret: encryptedSecret)
|> mapError { _ -> GenerateSecureSecretError in
return .generic
}
|> map { _ -> Data in
return secretData
}
}
public struct SecureIdAccessContext {
let secret: Data
}
public enum SecureIdAccessError {
case generic
case passwordError(AuthorizationPasswordVerificationError)
case secretPasswordMismatch
}
public func accessSecureId(network: Network, password: String) -> Signal<SecureIdAccessContext, SecureIdAccessError> {
return requestTwoStepVerifiationSettings(network: network, password: password)
|> mapError { error -> SecureIdAccessError in
return .passwordError(error)
}
|> mapToSignal { settings -> Signal<SecureIdAccessContext, SecureIdAccessError> in
if let secureSecret = settings.secureSecret {
if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: secureSecret, password: "q") { //password
return .single(SecureIdAccessContext(secret: decryptedSecret))
} else {
return .fail(.secretPasswordMismatch)
}
} else {
return generateSecureSecret(network: network, password: password)
|> mapError { _ -> SecureIdAccessError in
return SecureIdAccessError.generic
}
|> map { decryptedSecret in
return SecureIdAccessContext(secret: decryptedSecret)
}
}
}
}

View File

@@ -336,12 +336,12 @@ public func accountWithId(networkArguments: NetworkInitializationArguments, id:
}
public struct TwoStepAuthData {
let nextSalt: Data
let currentSalt: Data?
let hasRecovery: Bool
let currentHint: String?
let unconfirmedEmailPattern: String?
let secretRandom: Data
public let nextSalt: Data
public let currentSalt: Data?
public let hasRecovery: Bool
public let currentHint: String?
public let unconfirmedEmailPattern: String?
public let secretRandom: Data
}
public func twoStepAuthData(_ network: Network) -> Signal<TwoStepAuthData, MTRpcError> {
@@ -378,6 +378,17 @@ func sha256Digest(_ data : Data) -> Data {
return res
}
func sha512Digest(_ data : Data) -> Data {
var res = Data()
res.count = Int(CC_SHA512_DIGEST_LENGTH)
res.withUnsafeMutableBytes { mutableBytes -> Void in
data.withUnsafeBytes { bytes -> Void in
CC_SHA512(bytes, CC_LONG(data.count), mutableBytes)
}
}
return res
}
public func verifyPassword(_ account: UnauthorizedAccount, password: String) -> Signal<Api.auth.Authorization, MTRpcError> {
return twoStepAuthData(account.network)
|> mapToSignal { authData -> Signal<Api.auth.Authorization, MTRpcError> in

View File

@@ -13,7 +13,14 @@ public enum RequestSecureIdFormError {
case generic
}
private func parseFieldType(_ type: Api.AuthFieldType) -> SecureIdFieldType {
public enum RequestedSecureIdField {
case identity
case address
case phone
case email
}
private func parseRequestedFieldType(_ type: Api.AuthFieldType) -> RequestedSecureIdField {
switch type {
case .authFieldTypeIdentity:
return .identity
@@ -35,7 +42,7 @@ private func parseFileReference(_ file: Api.SecureFile) -> SecureIdFileReference
}
}
private func parseValue(_ value: Api.SecureValue) -> SecureIdFieldValue {
/*private func parseValue(_ value: Api.SecureValue) -> SecureIdFieldValue {
switch value {
case let .secureValueEmpty(name):
return SecureIdFieldValue(name: name, data: .none)
@@ -46,16 +53,75 @@ private func parseValue(_ value: Api.SecureValue) -> SecureIdFieldValue {
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:
return nil
}
}
private func parseField(_ field: Api.AuthField) -> SecureIdField {
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):
return SecureIdField(type: parseFieldType(type), value: parseValue(data))
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
}
public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: PeerId, scope: [String], origin: String?, packageName: String?, bundleId: String?, publicKey: String?) -> Signal<SecureIdForm, RequestSecureIdFormError> {
public struct EncryptedSecureIdForm {
public let peerId: PeerId
public let requestedFields: [RequestedSecureIdField]
let encryptedFields: [Api.AuthField]
}
public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: PeerId, scope: [String], origin: String?, packageName: String?, bundleId: String?, publicKey: String?) -> Signal<EncryptedSecureIdForm, RequestSecureIdFormError> {
if peerId.namespace != Namespaces.Peer.CloudUser {
return .fail(.generic)
}
@@ -76,10 +142,10 @@ public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: Peer
|> mapError { _ -> RequestSecureIdFormError in
return .generic
}
|> mapToSignal { result -> Signal<SecureIdForm, RequestSecureIdFormError> in
return postbox.modify { modifier -> SecureIdForm in
|> mapToSignal { result -> Signal<EncryptedSecureIdForm, RequestSecureIdFormError> in
return postbox.modify { modifier -> EncryptedSecureIdForm in
switch result {
case let .authorizationForm(_, botId, fields, acceptedFields, users):
case let .authorizationForm(_, botId, fields, _, users):
var peers: [Peer] = []
for user in users {
let parsed = TelegramUser(user: user)
@@ -89,10 +155,17 @@ public func requestSecureIdForm(postbox: Postbox, network: Network, peerId: Peer
return updated
})
let parsedFields = fields.map(parseField)
return SecureIdForm(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: botId), fields: parsedFields)
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)
}
} |> 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))
}

View File

@@ -0,0 +1,43 @@
import Foundation
public struct SecureIdDate: Equatable {
private var timestamp: Int32
public init(timestamp: Int32) {
self.timestamp = timestamp
}
public static func ==(lhs: SecureIdDate, rhs: SecureIdDate) -> Bool {
if lhs.timestamp != rhs.timestamp {
return false
}
return true
}
}
public enum SecureIdGender {
case male
case female
}
public enum SecureIdFileReference: Equatable {
case none
case file(id: Int64, accessHash: Int64, size: Int32, datacenterId: Int32, fileHash: String)
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
}
}
}
}

View File

@@ -0,0 +1,16 @@
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
}
}

View File

@@ -5,36 +5,77 @@ import Foundation
import Postbox
#endif
public enum SecureIdFieldType {
case identity
case address
case phone
case email
public enum SecureIdFieldValue<T>: Equatable where T: Equatable {
case empty
case value(T)
public static func ==(lhs: SecureIdFieldValue<T>, rhs: SecureIdFieldValue<T>) -> Bool {
switch lhs {
case .empty:
if case .empty = rhs {
return true
} else {
return false
}
case let .value(value):
if case .value(value) = rhs {
return true
} else {
return false
}
}
}
}
public enum SecureIdFileReference {
case none
case file(id: Int64, accessHash: Int64, size: Int32, datacenterId: Int32, fileHash: String)
public struct SecureIdFields: Equatable {
public var identity: SecureIdFieldValue<SecureIdIdentityField>?
public var phone: SecureIdFieldValue<SecureIdPhoneField>?
public var email: SecureIdFieldValue<SecureIdEmailField>?
public static func ==(lhs: SecureIdFields, rhs: SecureIdFields) -> Bool {
if lhs.identity != rhs.identity {
return false
}
if lhs.phone != rhs.phone {
return false
}
if lhs.email != rhs.email {
return false
}
return true
}
}
public enum SecureIdFieldValueData {
case none
case data(data: Data, hash: String, secret: Data)
case files(files: [SecureIdFileReference], hash: String, secret: Data)
case text(text: String, hash: String)
}
public enum SecureIdField: Equatable {
case identity(SecureIdIdentityField)
case phone(SecureIdPhoneField)
case email(SecureIdEmailField)
public struct SecureIdFieldValue {
public let name: String
public let data: SecureIdFieldValueData
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 SecureIdField {
public let type: SecureIdFieldType
public let value: SecureIdFieldValue
}
public struct SecureIdForm {
public let peerId: PeerId
public let fields: [SecureIdField]
public let fields: SecureIdFields
}

View File

@@ -0,0 +1,16 @@
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
}
}

View File

@@ -0,0 +1,41 @@
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
}
}

View File

@@ -0,0 +1,16 @@
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
}
}

View File

@@ -29,10 +29,11 @@ public func twoStepVerificationConfiguration(account: Account) -> Signal<TwoStep
public struct TwoStepVerificationSettings {
public let email: String
public let secureSecret: Data?
}
public func requestTwoStepVerifiationSettings(account: Account, password: String) -> Signal<TwoStepVerificationSettings, AuthorizationPasswordVerificationError> {
return twoStepAuthData(account.network)
public func requestTwoStepVerifiationSettings(network: Network, password: String) -> Signal<TwoStepVerificationSettings, AuthorizationPasswordVerificationError> {
return twoStepAuthData(network)
|> mapToSignal { authData -> Signal<TwoStepVerificationSettings, MTRpcError> in
var data = Data()
data.append(authData.currentSalt!)
@@ -40,11 +41,11 @@ public func requestTwoStepVerifiationSettings(account: Account, password: String
data.append(authData.currentSalt!)
let currentPasswordHash = sha256Digest(data)
return account.network.request(Api.functions.account.getPasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false)
return network.request(Api.functions.account.getPasswordSettings(currentPasswordHash: Buffer(data: currentPasswordHash)), automaticFloodWait: false)
|> map { result -> TwoStepVerificationSettings in
switch result {
case let .passwordSettings(email, _):
return TwoStepVerificationSettings(email: email)
case let .passwordSettings(email, secureSecret):
return TwoStepVerificationSettings(email: email, secureSecret: secureSecret.size == 0 ? nil : secureSecret.makeData())
}
}
}
@@ -74,12 +75,25 @@ public enum UpdatedTwoStepVerificationPassword {
case password(password: String, hint: String, email: String?)
}
public func updateTwoStepVerificationPassword(account: Account, currentPassword: String?, updatedPassword: UpdatedTwoStepVerificationPassword) -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> {
return twoStepAuthData(account.network)
public func updateTwoStepVerificationPassword(network: Network, currentPassword: String?, updatedPassword: UpdatedTwoStepVerificationPassword) -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> {
return twoStepAuthData(network)
|> mapError { _ -> UpdateTwoStepVerificationPasswordError in
return .generic
}
|> mapToSignal { authData -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in
|> mapToSignal { authData -> Signal<(TwoStepAuthData, Data?), UpdateTwoStepVerificationPasswordError> in
if authData.currentSalt != nil {
return requestTwoStepVerifiationSettings(network: network, password: currentPassword ?? "")
|> mapError { _ -> UpdateTwoStepVerificationPasswordError in
return .generic
}
|> map { settings in
return (authData, settings.secureSecret)
}
} else {
return .single((authData, nil))
}
}
|> mapToSignal { authData, secureSecret -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> in
let currentPasswordHash: Buffer
if let currentSalt = authData.currentSalt {
var data = Data()
@@ -100,7 +114,7 @@ public func updateTwoStepVerificationPassword(account: Account, currentPassword:
flags |= (1 << 0)
}
return account.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: "", newSecureSecret: nil)), automaticFloodWait: false)
|> mapError { _ -> UpdateTwoStepVerificationPasswordError in
return .generic
}
@@ -126,14 +140,24 @@ public func updateTwoStepVerificationPassword(account: Account, currentPassword:
updatedData.append(password.data(using: .utf8, allowLossyConversion: true)!)
updatedData.append(nextSalt)
var updatedSecureSecret: Data?
if let encryptedSecret = secureSecret {
flags |= 1 << 2
if let decryptedSecret = decryptedSecureSecret(encryptedSecretData: encryptedSecret, password: currentPassword ?? "") {
updatedSecureSecret = encryptedSecureSecret(secretData: decryptedSecret, password: password)
} else {
updatedSecureSecret = Data()
}
}
let updatedPasswordHash = sha256Digest(updatedData)
return account.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: nil)), 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, newSecureSecret: updatedSecureSecret.flatMap(Buffer.init))), automaticFloodWait: false)
|> map { _ -> UpdateTwoStepVerificationPasswordResult in
return .password(password: password, pendingEmailPattern: nil)
}
|> `catch` { error -> Signal<UpdateTwoStepVerificationPasswordResult, MTRpcError> in
if error.errorDescription == "EMAIL_UNCONFIRMED" {
return twoStepAuthData(account.network)
return twoStepAuthData(network)
|> map { result -> UpdateTwoStepVerificationPasswordResult in
return .password(password: password, pendingEmailPattern: result.unconfirmedEmailPattern)
}
@@ -152,6 +176,41 @@ public func updateTwoStepVerificationPassword(account: Account, currentPassword:
}
}
enum UpdateTwoStepVerificationSecureSecretResult {
case success
}
enum UpdateTwoStepVerificationSecureSecretError {
case generic
}
func updateTwoStepVerificationSecureSecret(network: Network, password: String, updatedSecret: Data) -> Signal<UpdateTwoStepVerificationSecureSecretResult, UpdateTwoStepVerificationSecureSecretError> {
return twoStepAuthData(network)
|> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in
return .generic
}
|> mapToSignal { authData -> Signal<UpdateTwoStepVerificationSecureSecretResult, UpdateTwoStepVerificationSecureSecretError> in
guard let currentSalt = authData.currentSalt else {
return .fail(.generic)
}
var data = Data()
data.append(currentSalt)
data.append(password.data(using: .utf8, allowLossyConversion: true)!)
data.append(currentSalt)
let currentPasswordHash = Buffer(data: sha256Digest(data))
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)
|> mapError { _ -> UpdateTwoStepVerificationSecureSecretError in
return .generic
}
|> map { _ -> UpdateTwoStepVerificationSecureSecretResult in
return .success
}
}
}
public func updateTwoStepVerificationEmail(account: Account, currentPassword: String, updatedEmail: String) -> Signal<UpdateTwoStepVerificationPasswordResult, UpdateTwoStepVerificationPasswordError> {
return twoStepAuthData(account.network)
|> mapError { _ -> UpdateTwoStepVerificationPasswordError in