Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
fastlane/README.md
fastlane/report.xml
fastlane/test_output/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.xcscmblueprint
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
.DS_Store
*.dSYM
*.dSYM.zip
*.ipa
*/xcuserdata/*
MtProtoKit.xcodeproj/*
+34
View File
@@ -0,0 +1,34 @@
objc_library(
name = "MtProtoKit",
enable_modules = True,
module_name = "MtProtoKit",
srcs = glob([
"Sources/**/*.m",
"Sources/**/*.h",
]),
copts = [
"-Werror",
],
hdrs = glob([
"PublicHeaders/**/*.h",
]),
includes = [
"PublicHeaders",
],
deps = [
"//submodules/EncryptionProvider:EncryptionProvider",
],
sdk_frameworks = [
"Foundation",
"Security",
"SystemConfiguration",
"CFNetwork",
],
sdk_dylibs = [
"libz",
],
visibility = [
"//visibility:public",
],
)
+33
View File
@@ -0,0 +1,33 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MtProtoKit",
platforms: [.macOS(.v10_13)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MtProtoKit",
targets: ["MtProtoKit"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "EncryptionProvider", path: "../EncryptionProvider")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "MtProtoKit",
dependencies: [.product(name: "EncryptionProvider", package: "EncryptionProvider", condition: nil)],
path: ".",
exclude: ["BUILD"],
publicHeadersPath: "PublicHeaders",
cSettings: [
.headerSearchPath("PublicHeaders"),
]),
]
)
@@ -0,0 +1,88 @@
#import <Foundation/Foundation.h>
@interface MTProxySecret : NSObject <NSCoding>
@property (nonatomic, strong, readonly) NSData * _Nonnull secret;
+ (MTProxySecret * _Nullable)parse:(NSString * _Nonnull)string;
+ (MTProxySecret * _Nullable)parseData:(NSData * _Nonnull)data;
- (NSData * _Nonnull)serialize;
- (NSString * _Nonnull)serializeToString;
@end
@interface MTProxySecretType0 : MTProxySecret
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret;
@end
@interface MTProxySecretType1 : MTProxySecret
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret;
@end
@interface MTProxySecretType2 : MTProxySecret
@property (nonatomic, strong, readonly) NSString * _Nonnull domain;
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret domain:(NSString * _Nonnull)domain;
@end
@interface MTSocksProxySettings : NSObject
@property (nonatomic, strong, readonly) NSString * _Nonnull ip;
@property (nonatomic, readonly) uint16_t port;
@property (nonatomic, strong, readonly) NSString * _Nullable username;
@property (nonatomic, strong, readonly) NSString * _Nullable password;
@property (nonatomic, strong, readonly) NSData * _Nullable secret;
- (instancetype _Nonnull)initWithIp:(NSString * _Nonnull )ip port:(uint16_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password secret:(NSData * _Nullable)secret;
@end
@interface MTNetworkSettings : NSObject
@property (nonatomic, readonly) bool reducedBackupDiscoveryTimeout;
- (instancetype _Nonnull)initWithReducedBackupDiscoveryTimeout:(bool)reducedBackupDiscoveryTimeout;
@end
@interface MTApiEnvironment : NSObject
@property (nonatomic) int32_t apiId;
@property (nonatomic, strong, readonly) NSString * _Nullable deviceModel;
@property (nonatomic, strong, readonly) NSString * _Nullable deviceModelName;
@property (nonatomic, strong, readonly) NSString * _Nullable systemVersion;
@property (nonatomic, strong) NSString * _Nullable appVersion;
@property (nonatomic, strong, readonly) NSString * _Nullable systemLangCode;
@property (nonatomic, strong) NSNumber * _Nullable layer;
@property (nonatomic, strong, readonly) NSData * _Nullable systemCode;
@property (nonatomic, strong) NSString * _Nullable langPack;
@property (nonatomic, strong, readonly) NSString * _Nullable langPackCode;
@property (nonatomic, strong, readonly) NSString * _Nullable apiInitializationHash;
@property (nonatomic) bool disableUpdates;
@property (nonatomic) NSData * _Nullable tcpPayloadPrefix;
@property (nonatomic) NSDictionary * _Nullable datacenterAddressOverrides;
@property (nonatomic) NSString * _Nullable accessHostOverride;
@property (nonatomic, strong, readonly) MTSocksProxySettings * _Nullable socksProxySettings;
@property (nonatomic, strong, readonly) MTNetworkSettings * _Nullable networkSettings;
@property (nonatomic, copy) void (^ _Nullable passwordInputHandler)(void);
- (MTApiEnvironment * _Nonnull)withUpdatedLangPackCode:(NSString * _Nullable)langPackCode;
- (MTApiEnvironment * _Nonnull)withUpdatedSocksProxySettings:(MTSocksProxySettings * _Nullable)socksProxySettings;
- (MTApiEnvironment * _Nonnull)withUpdatedNetworkSettings:(MTNetworkSettings * _Nullable)networkSettings;
- (MTApiEnvironment * _Nonnull)withUpdatedSystemCode:(NSData * _Nullable)systemCode;
-(id _Nonnull)initWithDeviceModelName:(NSString * _Nullable)deviceModelName;
@end
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
@interface MTAtomic : NSObject
- (instancetype)initWithValue:(id)value;
- (id)swap:(id)newValue;
- (id)value;
- (id)modify:(id (^)(id))f;
- (id)with:(id (^)(id))f;
@end
@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@class MTContext;
@interface MTBackupAddressSignals : NSObject
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber mainDatacenterId:(NSInteger)mainDatacenterId;
@end
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
@interface MTBag : NSObject
- (NSInteger)addItem:(id)item;
- (void)enumerateItems:(void (^)(id))block;
- (void)removeItem:(NSInteger)key;
- (bool)isEmpty;
- (NSArray *)copyItems;
@end
@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTMessageService.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
@interface MTBindKeyMessageService : NSObject <MTMessageService>
- (instancetype)initWithPersistentKey:(MTDatacenterAuthKey *)persistentKey ephemeralKey:(MTDatacenterAuthKey *)ephemeralKey completion:(void (^)(bool))completion;
-(void)complete;
@end
@@ -0,0 +1,161 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTNetworkUsageCalculationInfo.h>
#import <EncryptionProvider/EncryptionProvider.h>
@class MTDatacenterAddress;
@class MTDatacenterAddressSet;
@protocol MTSerialization;
@class MTContext;
@class MTTransportScheme;
@protocol MTKeychain;
@class MTSessionInfo;
@class MTApiEnvironment;
@class MTSignal;
@class MTQueue;
@protocol MTTcpConnectionInterface;
@protocol MTTcpConnectionInterfaceDelegate <NSObject>
- (void)connectionInterfaceDidReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;
- (void)connectionInterfaceDidReadData:(NSData * _Nonnull)rawData withTag:(long)tag networkType:(int32_t)networkType;
- (void)connectionInterfaceDidConnect;
- (void)connectionInterfaceDidDisconnectWithError:(NSError * _Nullable)error;
@end
@protocol MTTcpConnectionInterface<NSObject>
- (void)setGetLogPrefix:(NSString * _Nonnull(^_Nullable)())getLogPrefix;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo * _Nullable)usageCalculationInfo;
- (bool)connectToHost:(NSString * _Nonnull)inHost
onPort:(uint16_t)port
viaInterface:(NSString * _Nullable)inInterface
withTimeout:(NSTimeInterval)timeout
error:(NSError * _Nullable * _Nullable)errPtr;
- (void)writeData:(NSData * _Nonnull)data;
- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;
- (void)disconnect;
- (void)resetDelegate;
@end
@protocol MTContextChangeListener <NSObject>
@optional
- (void)contextDatacenterAddressSetUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId addressSet:(MTDatacenterAddressSet * _Nonnull)addressSet;
- (void)contextDatacenterAuthInfoUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId authInfo:(MTDatacenterAuthInfo * _Nonnull)authInfo selector:(MTDatacenterAuthInfoSelector)selector;
- (void)contextDatacenterAuthTokenUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId authToken:(id _Nullable)authToken;
- (void)contextDatacenterTransportSchemesUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId shouldReset:(bool)shouldReset;
- (void)contextIsPasswordRequiredUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId;
- (void)contextDatacenterPublicKeysUpdated:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> * _Nonnull)publicKeys;
- (MTSignal * _Nonnull)fetchContextDatacenterPublicKeys:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId;
- (void)contextApiEnvironmentUpdated:(MTContext * _Nonnull)context apiEnvironment:(MTApiEnvironment * _Nonnull)apiEnvironment;
- (MTSignal * _Nonnull)isContextNetworkAccessAllowed:(MTContext * _Nonnull)context;
- (void)contextLoggedOut:(MTContext * _Nonnull)context;
@end
@interface MTContextBlockChangeListener : NSObject <MTContextChangeListener>
@property (nonatomic, copy) void (^ _Nullable contextIsPasswordRequiredUpdated)(MTContext * _Nonnull, NSInteger);
@property (nonatomic, copy) MTSignal * _Nonnull (^ _Nullable fetchContextDatacenterPublicKeys)(MTContext * _Nonnull, NSInteger);
@property (nonatomic, copy) MTSignal * _Nonnull(^ _Nullable isContextNetworkAccessAllowed)(MTContext * _Nonnull);
@end
@interface MTContext : NSObject
@property (nonatomic, strong) id<MTKeychain> _Nonnull keychain;
@property (nonatomic, strong, readonly) id<MTSerialization> _Nonnull serialization;
@property (nonatomic, strong) id<EncryptionProvider> _Nonnull encryptionProvider;
@property (nonatomic, strong, readonly) MTApiEnvironment * _Nonnull apiEnvironment;
@property (nonatomic, readonly) bool isTestingEnvironment;
@property (nonatomic, readonly) bool useTempAuthKeys;
@property (nonatomic) int32_t tempKeyExpiration;
@property (nonatomic, copy) id<MTTcpConnectionInterface> _Nonnull (^ _Nullable makeTcpConnectionInterface)(id<MTTcpConnectionInterfaceDelegate> _Nonnull delegate, dispatch_queue_t _Nonnull delegateQueue);
+ (int32_t)fixedTimeDifference;
+ (void)setFixedTimeDifference:(int32_t)fixedTimeDifference;
+ (MTQueue * _Nonnull)contextQueue;
+ (void)performWithObjCTry:(dispatch_block_t _Nonnull)block;
+ (void)copyAuthInfoFrom:(id<MTKeychain> _Nonnull)keychain toTempKeychain:(id<MTKeychain> _Nonnull)tempKeychain;
- (instancetype _Nonnull)initWithSerialization:(id<MTSerialization> _Nonnull)serialization encryptionProvider:(id<EncryptionProvider> _Nonnull)encryptionProvider apiEnvironment:(MTApiEnvironment * _Nonnull)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys;
- (void)performBatchUpdates:(void (^ _Nonnull)())block;
- (void)addChangeListener:(id<MTContextChangeListener> _Nonnull)changeListener;
- (void)removeChangeListener:(id<MTContextChangeListener> _Nonnull)changeListener;
- (void)setDiscoverBackupAddressListSignal:(MTSignal * _Nonnull)signal;
- (void)setExternalRequestVerification:(MTSignal * _Nonnull (^ _Nonnull)(NSString * _Nonnull))externalRequestVerification;
- (void)setExternalRecaptchaRequestVerification:(MTSignal * _Nonnull (^ _Nonnull)(NSString * _Nonnull, NSString * _Nonnull))externalRecaptchaRequestVerification;
- (MTSignal * _Nullable)performExternalRequestVerificationWithNonce:(NSString * _Nonnull)nonce;
- (MTSignal * _Nullable)performExternalRecaptchaRequestVerificationWithMethod:(NSString * _Nonnull)method siteKey:(NSString * _Nonnull)siteKey;
- (NSTimeInterval)globalTime;
- (NSTimeInterval)globalTimeDifference;
- (NSTimeInterval)globalTimeOffsetFromUTC;
- (void)setGlobalTimeDifference:(NSTimeInterval)globalTimeDifference;
- (void)setSeedAddressSetForDatacenterWithId:(NSInteger)datacenterId seedAddressSet:(MTDatacenterAddressSet * _Nonnull)seedAddressSet;
- (void)updateAddressSetForDatacenterWithId:(NSInteger)datacenterId addressSet:(MTDatacenterAddressSet * _Nonnull)addressSet forceUpdateSchemes:(bool)forceUpdateSchemes;
- (void)addAddressForDatacenterWithId:(NSInteger)datacenterId address:(MTDatacenterAddress * _Nonnull)address;
- (void)updateTransportSchemeForDatacenterWithId:(NSInteger)datacenterId transportScheme:(MTTransportScheme * _Nonnull)transportScheme media:(bool)media isProxy:(bool)isProxy;
- (void)updateAuthInfoForDatacenterWithId:(NSInteger)datacenterId authInfo:(MTDatacenterAuthInfo * _Nullable)authInfo selector:(MTDatacenterAuthInfoSelector)selector;
- (bool)isPasswordInputRequiredForDatacenterWithId:(NSInteger)datacenterId;
- (bool)updatePasswordInputRequiredForDatacenterWithId:(NSInteger)datacenterId required:(bool)required;
- (void)scheduleSessionCleanupForAuthKeyId:(int64_t)authKeyId sessionInfo:(MTSessionInfo * _Nonnull)sessionInfo;
- (void)collectSessionIdsForCleanupWithAuthKeyId:(int64_t)authKeyId completion:(void (^ _Nonnull)(NSArray * _Nonnull sessionIds))completion;
- (void)sessionIdsDeletedForAuthKeyId:(int64_t)authKeyId sessionIds:(NSArray * _Nonnull)sessionIds;
- (NSArray * _Nonnull)knownDatacenterIds;
- (void)enumerateAddressSetsForDatacenters:(void (^ _Nonnull)(NSInteger datacenterId, MTDatacenterAddressSet * _Nonnull addressSet, BOOL * _Nullable stop))block;
- (MTDatacenterAddressSet * _Nonnull)addressSetForDatacenterWithId:(NSInteger)datacenterId;
- (void)reportTransportSchemeFailureForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme * _Nonnull)transportScheme;
- (void)reportTransportSchemeSuccessForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme * _Nonnull)transportScheme;
- (void)invalidateTransportSchemesForDatacenterIds:(NSArray<NSNumber *> * _Nonnull)datacenterIds;
- (void)invalidateTransportSchemesForKnownDatacenterIds;
- (MTTransportScheme * _Nullable)chooseTransportSchemeForConnectionToDatacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes;
- (NSArray<MTTransportScheme *> * _Nonnull)transportSchemesForDatacenterWithId:(NSInteger)datacenterId media:(bool)media enforceMedia:(bool)enforceMedia isProxy:(bool)isProxy;
- (void)transportSchemeForDatacenterWithIdRequired:(NSInteger)datacenterId media:(bool)media;
- (void)invalidateTransportSchemeForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme * _Nonnull)transportScheme isProbablyHttp:(bool)isProbablyHttp media:(bool)media;
- (void)revalidateTransportSchemeForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme * _Nonnull)transportScheme media:(bool)media;
- (MTDatacenterAuthInfo * _Nullable)authInfoForDatacenterWithId:(NSInteger)datacenterId selector:(MTDatacenterAuthInfoSelector)selector;
- (NSArray<NSDictionary *> * _Nonnull)publicKeysForDatacenterWithId:(NSInteger)datacenterId;
- (void)updatePublicKeysForDatacenterWithId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> * _Nonnull)publicKeys;
- (void)publicKeysForDatacenterWithIdRequired:(NSInteger)datacenterId;
- (void)removeAllAuthTokens;
- (void)removeTokenForDatacenterWithId:(NSInteger)datacenterId;
- (id _Nullable)authTokenForDatacenterWithId:(NSInteger)datacenterId;
- (void)updateAuthTokenForDatacenterWithId:(NSInteger)datacenterId authToken:(id _Nullable)authToken;
- (void)addressSetForDatacenterWithIdRequired:(NSInteger)datacenterId;
- (void)authInfoForDatacenterWithIdRequired:(NSInteger)datacenterId isCdn:(bool)isCdn selector:(MTDatacenterAuthInfoSelector)selector allowUnboundEphemeralKeys:(bool)allowUnboundEphemeralKeys;
- (void)authTokenForDatacenterWithIdRequired:(NSInteger)datacenterId authToken:(id _Nullable)authToken masterDatacenterId:(NSInteger)masterDatacenterId;
- (void)reportProblemsWithDatacenterAddressForId:(NSInteger)datacenterId address:(MTDatacenterAddress * _Nonnull)address;
- (void)updateApiEnvironment:(MTApiEnvironment * _Nullable (^ _Nonnull)(MTApiEnvironment * _Nullable))f;
- (void)beginExplicitBackupAddressDiscovery;
- (void)checkIfLoggedOut:(NSInteger)datacenterId;
@end
@@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
@interface MTDatacenterAddress : NSObject <NSCoding, NSCopying>
@property (nonatomic, strong, readonly) NSString * _Nullable host;
@property (nonatomic, strong, readonly) NSString * _Nullable ip;
@property (nonatomic, readonly) uint16_t port;
@property (nonatomic, readonly) bool preferForMedia;
@property (nonatomic, readonly) bool restrictToTcp;
@property (nonatomic, readonly) bool cdn;
@property (nonatomic, readonly) bool preferForProxy;
@property (nonatomic, readonly) NSData * _Nullable secret;
- (instancetype _Nonnull)initWithIp:(NSString * _Nonnull)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy secret:(NSData * _Nullable)secret;
- (BOOL)isEqualToAddress:(MTDatacenterAddress * _Nonnull)other;
- (BOOL)isIpv6;
@end
@@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
@interface MTDatacenterAddressListData : NSObject
@property (nonatomic, strong, readonly) NSDictionary<NSNumber *, NSArray *> *addressList;
- (instancetype)initWithAddressList:(NSDictionary<NSNumber *, NSArray *> *)addressList;
@end
@@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
@class MTDatacenterAddress;
@interface MTDatacenterAddressSet : NSObject <NSCoding>
@property (nonatomic, strong, readonly) NSArray *addressList;
- (instancetype)initWithAddressList:(NSArray *)addressList;
- (MTDatacenterAddress *)firstAddress;
@end
@@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
@class MTContext;
@interface MTDatacenterAuthAction : NSObject
- (instancetype)initWithAuthKeyInfoSelector:(MTDatacenterAuthInfoSelector)authKeyInfoSelector isCdn:(bool)isCdn skipBind:(bool)skipBind completion:(void (^)(MTDatacenterAuthAction *, bool))completion;
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId;
- (void)cancel;
@end
@@ -0,0 +1,35 @@
#import <Foundation/Foundation.h>
@interface MTDatacenterAuthKey: NSObject <NSCoding>
@property (nonatomic, strong, readonly) NSData *authKey;
@property (nonatomic, readonly) int64_t authKeyId;
@property (nonatomic, readonly) int32_t validUntilTimestamp;
@property (nonatomic, readonly) bool notBound;
- (instancetype)initWithAuthKey:(NSData *)tempAuthKey authKeyId:(int64_t)authKeyId validUntilTimestamp:(int32_t)validUntilTimestamp notBound:(bool)notBound;
@end
typedef NS_ENUM(int64_t, MTDatacenterAuthInfoSelector) {
MTDatacenterAuthInfoSelectorPersistent = 0,
MTDatacenterAuthInfoSelectorEphemeralMain,
MTDatacenterAuthInfoSelectorEphemeralMedia
};
@interface MTDatacenterAuthInfo : NSObject <NSCoding>
@property (nonatomic, strong, readonly) NSData *authKey;
@property (nonatomic, readonly) int64_t authKeyId;
@property (nonatomic, readonly) int32_t validUntilTimestamp;
@property (nonatomic, strong, readonly) NSArray *saltSet;
@property (nonatomic, strong, readonly) NSDictionary *authKeyAttributes;
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId validUntilTimestamp:(int32_t)validUntilTimestamp saltSet:(NSArray *)saltSet authKeyAttributes:(NSDictionary *)authKeyAttributes;
- (int64_t)authSaltForMessageId:(int64_t)messageId;
- (MTDatacenterAuthInfo *)mergeSaltSet:(NSArray *)updatedSaltSet forTimestamp:(NSTimeInterval)timestamp;
- (MTDatacenterAuthInfo *)withUpdatedAuthKeyAttributes:(NSDictionary *)authKeyAttributes;
@end
@@ -0,0 +1,21 @@
#import <MtProtoKit/MTMessageService.h>
@class MTContext;
@class MTDatacenterAuthMessageService;
@class MTDatacenterAuthKey;
@protocol MTDatacenterAuthMessageServiceDelegate <NSObject>
- (void)authMessageServiceCompletedWithAuthKey:(MTDatacenterAuthKey *)authKey timestamp:(int64_t)timestamp;
@end
@interface MTDatacenterAuthMessageService : NSObject <MTMessageService>
@property (nonatomic, weak) id<MTDatacenterAuthMessageServiceDelegate> delegate;
- (instancetype)initWithContext:(MTContext *)context tempAuth:(bool)tempAuth;
@end
@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
@interface MTDatacenterSaltInfo : NSObject <NSCoding>
@property (nonatomic, readonly) int64_t salt;
@property (nonatomic, readonly) int64_t firstValidMessageId;
@property (nonatomic, readonly) int64_t lastValidMessageId;
- (instancetype)initWithSalt:(int64_t)salt firstValidMessageId:(int64_t)firstValidMessageId lastValidMessageId:(int64_t)lastValidMessageId;
- (int64_t)validMessageCountAfterId:(int64_t)messageId;
- (bool)isValidFutureSaltForMessageId:(int64_t)messageId;
@end
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
@class MTContext;
@class MTDatacenterTransferAuthAction;
@protocol MTDatacenterTransferAuthActionDelegate <NSObject>
- (void)datacenterTransferAuthActionCompleted:(MTDatacenterTransferAuthAction *)action;
@end
@interface MTDatacenterTransferAuthAction : NSObject
@property (nonatomic, weak) id<MTDatacenterTransferAuthActionDelegate> delegate;
- (void)execute:(MTContext *)context masterDatacenterId:(NSInteger)masterDatacenterId destinationDatacenterId:(NSInteger)destinationDatacenterId authToken:(id)authToken;
- (void)cancel;
@end
@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
@interface MTDatacenterVerificationData : NSObject
@property (nonatomic, readonly) NSInteger datacenterId;
@property (nonatomic, readonly) bool isTestingEnvironment;
- (instancetype _Nonnull)initWithDatacenterId:(NSInteger)datacenterId isTestingEnvironment:(bool)isTestingEnvironment;
@end
@@ -0,0 +1,26 @@
#import <Foundation/Foundation.h>
@protocol MTDisposable <NSObject>
- (void)dispose;
@end
@interface MTBlockDisposable : NSObject <MTDisposable>
- (instancetype)initWithBlock:(void (^)())block;
@end
@interface MTMetaDisposable : NSObject <MTDisposable>
- (void)setDisposable:(id<MTDisposable>)disposable;
@end
@interface MTDisposableSet : NSObject <MTDisposable>
- (void)add:(id<MTDisposable>)disposable;
- (void)remove:(id<MTDisposable>)disposable;
@end
@@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
@interface MTDropResponseContext : NSObject
@property (nonatomic, readonly) int64_t dropMessageId;
@property (nonatomic) int64_t messageId;
@property (nonatomic) int32_t messageSeqNo;
- (instancetype)initWithDropMessageId:(int64_t)dropMessageId;
@end
@@ -0,0 +1,91 @@
#ifndef MTEncryption_H
#define MTEncryption_H
#import <Foundation/Foundation.h>
#import <EncryptionProvider/EncryptionProvider.h>
#ifdef __cplusplus
extern "C" {
#endif
NSData * _Nonnull MTSha1(NSData * _Nonnull data);
NSData * _Nonnull MTSubdataSha1(NSData * _Nonnull data, NSUInteger offset, NSUInteger length);
NSData * _Nonnull MTSha256(NSData * _Nonnull data);
void MTRawSha1(void const * _Nonnull inData, NSUInteger length, void * _Nonnull outData);
void MTRawSha256(void const * _Nonnull inData, NSUInteger length, void * _Nonnull outData);
int32_t MTMurMurHash32(const void * _Nonnull bytes, int length);
void MTAesEncryptInplace(NSMutableData * _Nonnull data, NSData * _Nonnull key, NSData * _Nonnull iv);
void MTAesEncryptInplaceAndModifyIv(NSMutableData * _Nonnull data, NSData * _Nonnull key, NSMutableData * _Nonnull iv);
void MTAesEncryptBytesInplaceAndModifyIv(void * _Nonnull data, NSInteger length, NSData * _Nonnull key, void * _Nonnull iv);
void MTAesEncryptRaw(void const * _Nonnull data, void * _Nonnull outData, NSInteger length, void const * _Nonnull key, void const * _Nonnull iv);
void MTAesDecryptRaw(void const * _Nonnull data, void * _Nonnull outData, NSInteger length, void const * _Nonnull key, void const * _Nonnull iv);
void MTAesDecryptInplaceAndModifyIv(NSMutableData * _Nonnull data, NSData * _Nonnull key, NSMutableData * _Nonnull iv);
void MTAesDecryptBytesInplaceAndModifyIv(void * _Nonnull data, NSInteger length, NSData * _Nonnull key, void * _Nonnull iv);
NSData * _Nullable MTAesEncrypt(NSData * _Nonnull data, NSData * _Nonnull key, NSData * _Nonnull iv);
NSData * _Nullable MTAesDecrypt(NSData * _Nonnull data, NSData * _Nonnull key, NSData * _Nonnull iv);
NSData * _Nullable MTRsaEncrypt(id<EncryptionProvider> _Nonnull provider, NSString * _Nonnull publicKey, NSData * _Nonnull data);
NSData * _Nullable MTExp(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull base, NSData * _Nonnull exp, NSData * _Nonnull modulus);
NSData * _Nullable MTModSub(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull a, NSData * _Nonnull b, NSData * _Nonnull modulus);
NSData * _Nullable MTModMul(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull a, NSData * _Nonnull b, NSData * _Nonnull modulus);
NSData * _Nullable MTMul(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull a, NSData * _Nonnull b);
NSData * _Nullable MTAdd(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull a, NSData * _Nonnull b);
bool MTFactorize(uint64_t what, uint64_t * _Nonnull resA, uint64_t * _Nonnull resB);
bool MTIsZero(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull value);
NSData * _Nullable MTAesCtrDecrypt(NSData * _Nonnull data, NSData * _Nonnull key, NSData * _Nonnull iv);
@protocol MTKeychain;
bool MTCheckIsSafeG(unsigned int g);
bool MTCheckIsSafeB(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull b, NSData * _Nonnull p);
bool MTCheckIsSafePrime(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull numberBytes, id<MTKeychain> _Nonnull keychain);
bool MTCheckIsSafeGAOrB(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull gAOrB, NSData * _Nonnull p);
bool MTCheckMod(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull numberBytes, unsigned int g, id<MTKeychain> _Nonnull keychain);
@interface MTAesCtr : NSObject
- (instancetype _Nonnull)initWithKey:(const void * _Nonnull)key keyLength:(int)keyLength iv:(const void * _Nonnull)iv decrypt:(bool)decrypt;
- (instancetype _Nonnull)initWithKey:(const void * _Nonnull)key keyLength:(int)keyLength iv:(const void * _Nonnull)iv ecount:(void * _Nonnull)ecount num:(uint32_t)num;
- (uint32_t)num;
- (void * _Nonnull)ecount;
- (void)getIv:(void * _Nonnull)iv;
- (void)encryptIn:(const unsigned char * _Nonnull)in out:(unsigned char * _Nonnull)out len:(size_t)len;
@end
uint64_t MTRsaFingerprint(id<EncryptionProvider> _Nonnull provider, NSString * _Nonnull key);
NSData * _Nullable MTRsaEncryptPKCS1OAEP(id<EncryptionProvider> _Nonnull provider, NSString * _Nonnull key, NSData * _Nonnull data);
@interface MTBackupDatacenterAddress : NSObject
@property (nonatomic, readonly) int32_t datacenterId;
@property (nonatomic, strong, readonly) NSString * _Nonnull ip;
@property (nonatomic, readonly) int32_t port;
@property (nonatomic, strong, readonly) NSData * _Nullable secret;
@end
@interface MTBackupDatacenterData : NSObject
@property (nonatomic, readonly) int32_t timestamp;
@property (nonatomic, readonly) int32_t expirationDate;
@property (nonatomic, strong, readonly) NSArray<MTBackupDatacenterAddress *> * _Nonnull addressList;
@end
MTBackupDatacenterData * _Nullable MTIPDataDecode(id<EncryptionProvider> _Nonnull provider, NSData * _Nonnull data, NSString * _Nonnull phoneNumber);
NSData * _Nullable MTPBKDF2(NSData * _Nonnull data, NSData * _Nonnull salt, int rounds);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
@interface MTExportedAuthorizationData : NSObject
@property (nonatomic, strong, readonly) NSData *authorizationBytes;
@property (nonatomic, readonly) int64_t authorizationId;
- (instancetype)initWithAuthorizationBytes:(NSData *)authorizationBytes authorizationId:(int64_t)authorizationId;
@end
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MTGzip : NSObject
+ (NSData * _Nullable)decompress:(NSData *)data;
+ (NSData * _Nullable)compress:(NSData *)data;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@interface MTHttpResponse : NSObject
@property (nonatomic, strong, readonly) NSDictionary *headers;
@property (nonatomic, strong, readonly) NSData *data;
@end
@interface MTHttpRequestOperation : NSObject
+ (MTSignal *)dataForHttpUrl:(NSURL *)url;
+ (MTSignal *)dataForHttpUrl:(NSURL *)url headers:(NSDictionary *)headers;
@end
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
@interface MTIncomingMessage : NSObject
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t seqNo;
@property (nonatomic, readonly) int64_t authKeyId;
@property (nonatomic, readonly) int64_t sessionId;
@property (nonatomic, readonly) int64_t salt;
@property (nonatomic, readonly) NSTimeInterval timestamp;
@property (nonatomic, readonly) NSInteger size;
@property (nonatomic, strong, readonly) id body;
- (instancetype)initWithMessageId:(int64_t)messageId seqNo:(int32_t)seqNo authKeyId:(int64_t)authKeyId sessionId:(int64_t)sessionId salt:(int64_t)salt timestamp:(NSTimeInterval)timestamp size:(NSInteger)size body:(id)body;
@end
@@ -0,0 +1,25 @@
#import <Foundation/Foundation.h>
@interface MTInputStream : NSObject
- (instancetype)initWithData:(NSData *)data;
- (NSInputStream *)wrappedInputStream;
- (int32_t)readInt32;
- (int32_t)readInt32:(bool *)failed __attribute__((nonnull(1)));
- (int64_t)readInt64;
- (int64_t)readInt64:(bool *)failed __attribute__((nonnull(1)));
- (double)readDouble;
- (double)readDouble:(bool *)failed __attribute__((nonnull(1)));
- (NSData *)readData:(int)length;
- (NSData *)readData:(int)length failed:(bool *)failed __attribute__((nonnull(2)));
- (NSMutableData *)readMutableData:(NSUInteger)length;
- (NSMutableData *)readMutableData:(NSUInteger)length failed:(bool *)failed __attribute__((nonnull(2)));
- (NSString *)readString;
- (NSString *)readString:(bool *)failed __attribute__((nonnull(1)));
- (NSData *)readBytes;
- (NSData *)readBytes:(bool *)failed __attribute__((nonnull(1)));
@end
@@ -0,0 +1,51 @@
#ifndef MtProtoKit_MTInternalId_h
#define MtProtoKit_MTInternalId_h
#import <os/lock.h>
#define MTInternalId(name) MT##name##InternalId
#define MTInternalIdClass(name) \
@interface MT##name##InternalId : NSObject <NSCopying> \
{ \
NSUInteger _value; \
} \
\
@end \
\
@implementation MT##name##InternalId \
\
- (instancetype)init \
{ \
self = [super init]; \
if (self != nil) \
{ \
static int32_t nextValue = 1; \
_value = OSAtomicIncrement32(&nextValue); \
} \
return self; \
} \
\
- (BOOL)isEqual:(id)object \
{ \
return [object isKindOfClass:[MT##name##InternalId class]] && ((MT##name##InternalId *)object)->_value == _value; \
} \
\
- (NSUInteger)hash \
{ \
return _value; \
} \
\
- (instancetype)copyWithZone:(NSZone *)__unused zone \
{ \
MT##name##InternalId *another = [[MT##name##InternalId alloc] init]; \
if (another != nil) \
another->_value = _value; \
return another; \
} \
\
@end
#endif
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
@protocol MTKeychain <NSObject>
- (void)setObject:(id)object forKey:(NSString *)aKey group:(NSString *)group;
- (NSDictionary *)dictionaryForKey:(NSString *)aKey group:(NSString *)group;
- (NSNumber *)numberForKey:(NSString *)aKey group:(NSString *)group;
- (void)removeObjectForKey:(NSString *)aKey group:(NSString *)group;
@end
@interface MTDeprecated : NSObject
+ (id)unarchiveDeprecatedWithData:(NSData *)data;
@end
@@ -0,0 +1,24 @@
#ifndef MTLogging_H
#define MTLogging_H
#import <Foundation/Foundation.h>
#ifdef __cplusplus
extern "C" {
#endif
bool MTLogEnabled();
void MTLog(NSString *format, ...);
void MTLogWithPrefix(NSString *(^getLogPrefix)(), NSString *format, ...);
void MTShortLog(NSString *format, ...);
void MTLogSetLoggingFunction(void (*function)(NSString *));
void MTLogSetShortLoggingFunction(void (*function)(NSString *));
void MTLogSetEnabled(bool);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
@interface MTMessageEncryptionKey : NSObject
@property (nonatomic, strong, readonly) NSData *key;
@property (nonatomic, strong, readonly) NSData *iv;
+ (instancetype)messageEncryptionKeyForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient;
+ (instancetype)messageEncryptionKeyV2ForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient;
- (instancetype)initWithKey:(NSData *)key iv:(NSData *)iv;
@end
@@ -0,0 +1,45 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
@class MTProto;
@class MTIncomingMessage;
@class MTMessageTransaction;
@class MTApiEnvironment;
@class MTSessionInfo;
@class MTTransportScheme;
@protocol MTMessageService <NSObject>
@optional
- (void)mtProtoWillAddService:(MTProto *)mtProto;
- (void)mtProtoDidAddService:(MTProto *)mtProto;
- (void)mtProtoDidRemoveService:(MTProto *)mtProto;
- (void)mtProtoPublicKeysUpdated:(MTProto *)mtProto datacenterId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> *)publicKeys;
- (MTMessageTransaction *)mtProtoMessageTransaction:(MTProto *)mtProto authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector sessionInfo:(MTSessionInfo *)sessionInfo scheme:(MTTransportScheme *)scheme;
- (void)mtProtoDidChangeSession:(MTProto *)mtProto;
- (void)mtProtoServerDidChangeSession:(MTProto *)mtProto firstValidMessageId:(int64_t)firstValidMessageId otherValidMessageIds:(NSArray *)otherValidMessageIds;
- (void)mtProto:(MTProto *)mtProto receivedMessage:(MTIncomingMessage *)message authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector networkType:(int32_t)networkType;
- (void)mtProto:(MTProto *)mtProto receivedQuickAck:(int32_t)quickAckId;
- (void)mtProto:(MTProto *)mtProto transactionsMayHaveFailed:(NSArray *)transactionIds;
- (void)mtProtoAllTransactionsMayHaveFailed:(MTProto *)mtProto;
- (void)mtProto:(MTProto *)mtProto messageDeliveryFailed:(int64_t)messageId;
- (void)mtProto:(MTProto *)mtProto messageDeliveryConfirmed:(NSArray *)messageIds;
- (void)mtProto:(MTProto *)mtProto messageResendRequestFailed:(int64_t)messageId;
- (void)mtProto:(MTProto *)mtProto protocolErrorReceived:(int32_t)errorCode;
- (bool)mtProto:(MTProto *)mtProto shouldRequestMessageWithId:(int64_t)responseMessageId inResponseToMessageId:(int64_t)messageId currentTransactionId:(id)currentTransactionId;
- (void)mtProto:(MTProto *)mtProto updateReceiveProgressForToken:(id)progressToken progress:(float)progress packetLength:(NSInteger)packetLength;
- (void)mtProtoTransportActivityUpdated:(MTProto *)mtProto;
- (void)mtProtoNetworkAvailabilityChanged:(MTProto *)mtProto isNetworkAvailable:(bool)isNetworkAvailable;
- (void)mtProtoConnectionStateChanged:(MTProto *)mtProto isConnected:(bool)isConnected;
- (void)mtProtoConnectionContextUpdateStateChanged:(MTProto *)mtProto isUpdatingConnectionContext:(bool)isUpdatingConnectionContext;
- (void)mtProtoServiceTasksStateChanged:(MTProto *)mtProto isPerformingServiceTasks:(bool)isPerformingServiceTasks;
- (void)mtProtoAuthTokenUpdated:(MTProto *)mtProto;
- (void)mtProtoApiEnvironmentUpdated:(MTProto *)mtProto apiEnvironment:(MTApiEnvironment *)apiEnvironment;
@end
@@ -0,0 +1,22 @@
#import <Foundation/Foundation.h>
@interface MTMessageTransaction : NSObject
@property (nonatomic, strong, readonly) id internalId;
/*
* Can be invoked multiple times in case message transaction maps to multiple different transport transactions
*/
@property (nonatomic, copy) void (^completion)(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, NSDictionary *messageInternalIdToQuickAckId);
@property (nonatomic, copy) void (^prepared)(NSDictionary *messageInternalIdToPreparedMessage);
@property (nonatomic, copy) void (^failed)();
@property (nonatomic, strong) NSArray *messagePayload;
@property (nonatomic) bool allowServiceMode;
@property (nonatomic) bool requiresEncryption;
- (instancetype)initWithMessagePayload:(NSArray *)messagePayload prepared:(void (^)(NSDictionary *messageInternalIdToPreparedMessage))prepared failed:(void (^)())failed completion:(void (^)(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, NSDictionary *messageInternalIdToQuickAckId))completion;
@end
@@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
@class MTNetworkAvailability;
@protocol MTNetworkAvailabilityDelegate <NSObject>
@optional
- (void)networkAvailabilityChanged:(MTNetworkAvailability *)networkAvailability networkIsAvailable:(bool)networkIsAvailable;
@end
@interface MTNetworkAvailability : NSObject
@property (nonatomic, weak) id<MTNetworkAvailabilityDelegate> delegate;
- (instancetype)initWithDelegate:(id<MTNetworkAvailabilityDelegate>)delegate;
@end
@@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
@class MTQueue;
@interface MTNetworkUsageCalculationInfo : NSObject
@property (nonatomic, strong, readonly) NSString *filePath;
@property (nonatomic, readonly) int32_t incomingWWANKey;
@property (nonatomic, readonly) int32_t outgoingWWANKey;
@property (nonatomic, readonly) int32_t incomingOtherKey;
@property (nonatomic, readonly) int32_t outgoingOtherKey;
- (instancetype)initWithFilePath:(NSString *)filePath incomingWWANKey:(int32_t)incomingWWANKey outgoingWWANKey:(int32_t)outgoingWWANKey incomingOtherKey:(int32_t)incomingOtherKey outgoingOtherKey:(int32_t)outgoingOtherKey;
@end
@@ -0,0 +1,33 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@class MTNetworkUsageCalculationInfo;
typedef enum {
MTNetworkUsageManagerInterfaceWWAN,
MTNetworkUsageManagerInterfaceOther
} MTNetworkUsageManagerInterface;
typedef struct {
NSUInteger incomingBytes;
NSUInteger outgoingBytes;
} MTNetworkUsageManagerInterfaceStats;
@protocol MTNetworkUsageManagerProtocol <NSObject>
- (void)addIncomingBytes:(NSUInteger)incomingBytes interface:(MTNetworkUsageManagerInterface)interface;
- (void)addOutgoingBytes:(NSUInteger)outgoingBytes interface:(MTNetworkUsageManagerInterface)interface;
@end
@interface MTNetworkUsageManager : NSObject <MTNetworkUsageManagerProtocol>
- (instancetype)initWithInfo:(MTNetworkUsageCalculationInfo *)info;
- (void)addIncomingBytes:(NSUInteger)incomingBytes interface:(MTNetworkUsageManagerInterface)interface;
- (void)addOutgoingBytes:(NSUInteger)outgoingBytes interface:(MTNetworkUsageManagerInterface)interface;
- (void)resetKeys:(NSArray<NSNumber *> *)keys setKeys:(NSDictionary<NSNumber *, NSNumber *> *)setKeys completion:(void (^)())completion;
- (MTSignal *)currentStatsForKeys:(NSArray<NSNumber *> *)keys;
@end
@@ -0,0 +1,24 @@
#import <Foundation/Foundation.h>
@interface MTOutgoingMessage : NSObject
@property (nonatomic, strong, readonly) id internalId;
@property (nonatomic, strong, readonly) NSData *data;
@property (nonatomic, strong, readonly) id metadata;
@property (nonatomic, strong, readonly) NSString *additionalDebugDescription;
@property (nonatomic, strong, readonly) id shortMetadata;
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t messageSeqNo;
@property (nonatomic) bool requiresConfirmation;
@property (nonatomic) bool needsQuickAck;
@property (nonatomic) bool hasHighPriority;
@property (nonatomic) int64_t inResponseToMessageId;
@property (nonatomic, copy) id (^dynamicDecorator)(int64_t, NSData *currentData, NSMutableDictionary *messageInternalIdToPreparedMessage);
- (instancetype)initWithData:(NSData *)data metadata:(id)metadata additionalDebugDescription:(NSString *)additionalDebugDescription shortMetadata:(id)shortMetadata;
- (instancetype)initWithData:(NSData *)data metadata:(id)metadata additionalDebugDescription:(NSString *)additionalDebugDescription shortMetadata:(id)shortMetadata messageId:(int64_t)messageId messageSeqNo:(int32_t)messageSeqNo;
@end
@@ -0,0 +1,19 @@
#import <Foundation/Foundation.h>
@interface MTOutputStream : NSObject
- (NSOutputStream *)wrappedOutputStream;
- (NSData *)currentBytes;
- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)len;
- (void)writeInt32:(int32_t)value;
- (void)writeInt64:(int64_t)value;
- (void)writeDouble:(double)value;
- (void)writeData:(NSData *)data;
- (void)writeString:(NSString *)data;
- (void)writeBytes:(NSData *)data;
@end
@@ -0,0 +1,20 @@
#import <Foundation/Foundation.h>
@interface MTPreparedMessage : NSObject
@property (nonatomic, strong, readonly) id internalId;
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t seqNo;
@property (nonatomic, readonly) int64_t salt;
@property (nonatomic, strong, readonly) NSData *data;
@property (nonatomic, readonly) bool requiresConfirmation;
@property (nonatomic, readonly) bool hasHighPriority;
@property (nonatomic, readonly) int64_t inResponseToMessageId;
- (instancetype)initWithData:(NSData *)data messageId:(int64_t)messageId seqNo:(int32_t)seqNo salt:(int64_t)salt requiresConfirmation:(bool)requiresConfirmation hasHighPriority:(bool)hasHighPriority;
- (instancetype)initWithData:(NSData *)data messageId:(int64_t)messageId seqNo:(int32_t)seqNo salt:(int64_t)salt requiresConfirmation:(bool)requiresConfirmation hasHighPriority:(bool)hasHighPriority inResponseToMessageId:(int64_t)inResponseToMessageId;
@end
@@ -0,0 +1,85 @@
#import <Foundation/Foundation.h>
@protocol MTMessageService;
@class MTQueue;
@class MTContext;
@class MTNetworkUsageCalculationInfo;
@class MTApiEnvironment;
@class MTDatacenterAuthKey;
@class MTTransport;
@class MTProto;
@interface MTProtoConnectionState : NSObject
@property (nonatomic, readonly) bool isConnected;
@property (nonatomic, readonly) NSString *proxyAddress;
@property (nonatomic, readonly) bool proxyHasConnectionIssues;
@end
@protocol MTProtoDelegate <NSObject>
@optional
- (void)mtProtoNetworkAvailabilityChanged:(MTProto *)mtProto isNetworkAvailable:(bool)isNetworkAvailable;
- (void)mtProtoConnectionStateChanged:(MTProto *)mtProto state:(MTProtoConnectionState *)state;
- (void)mtProtoConnectionContextUpdateStateChanged:(MTProto *)mtProto isUpdatingConnectionContext:(bool)isUpdatingConnectionContext;
- (void)mtProtoServiceTasksStateChanged:(MTProto *)mtProto isPerformingServiceTasks:(bool)isPerformingServiceTasks;
@end
@interface MTProto : NSObject
@property (nonatomic, weak) id<MTProtoDelegate> delegate;
@property (nonatomic, strong, readonly) MTContext *context;
@property (nonatomic, strong, readonly) MTApiEnvironment *apiEnvironment;
@property (nonatomic) NSInteger datacenterId;
@property (nonatomic, strong) MTDatacenterAuthKey *useExplicitAuthKey;
@property (nonatomic, strong) MTTransport *tempConnectionForReuse;
@property (nonatomic, copy) void (^tempAuthKeyBindingResultUpdated)(bool);
@property (nonatomic) bool shouldStayConnected;
@property (nonatomic) bool useUnauthorizedMode;
@property (nonatomic) bool useTempAuthKeys;
@property (nonatomic) bool media;
@property (nonatomic) bool enforceMedia;
@property (nonatomic) bool cdn;
@property (nonatomic) bool allowUnboundEphemeralKeys;
@property (nonatomic) bool checkForProxyConnectionIssues;
@property (nonatomic) bool canResetAuthData;
@property (nonatomic) id requiredAuthToken;
@property (nonatomic) NSInteger authTokenMasterDatacenterId;
@property (nonatomic, strong) NSString *(^getLogPrefix)();
- (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo requiredAuthToken:(id)requiredAuthToken authTokenMasterDatacenterId:(NSInteger)authTokenMasterDatacenterId;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo;
- (void)pause;
- (void)resume;
- (void)stop;
- (void)finalizeSession;
- (void)addMessageService:(id<MTMessageService>)messageService;
- (void)removeMessageService:(id<MTMessageService>)messageService;
- (MTQueue *)messageServiceQueue;
- (void)requestTransportTransaction;
- (void)requestSecureTransportReset;
- (void)resetSessionInfo:(bool)ifActive;
- (void)requestTimeResync;
- (void)_messageResendRequestFailed:(int64_t)messageId;
+ (NSData *)_manuallyEncryptedMessage:(NSData *)preparedData messageId:(int64_t)messageId authKey:(MTDatacenterAuthKey *)authKey;
- (void)simulateDisconnection;
- (MTTransport *)takeConnectionForReusing;
@end
@@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTProtoPersistenceInterface.h>
NS_ASSUME_NONNULL_BEGIN
@interface MTProtoEngine : NSObject
- (instancetype)initWithPersistenceInterface:(id<MTProtoPersistenceInterface>)persistenceInterface;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTProtoEngine.h>
NS_ASSUME_NONNULL_BEGIN
@interface MTProtoInstance : NSObject
- (instancetype)initWithEngine:(MTProtoEngine *)engine;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,14 @@
#import <Foundation/Foundation.h>
@class MTSignal;
NS_ASSUME_NONNULL_BEGIN
@protocol MTProtoPersistenceInterface <NSObject>
- (MTSignal *)get:(NSData *)key;
- (void)set:(NSData *)key value:(NSData *)value;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@class MTContext;
@class MTSocksProxySettings;
@interface MTProxyConnectivityStatus : NSObject
@property (nonatomic, readonly) bool reachable;
@property (nonatomic, readonly) NSTimeInterval roundTripTime;
@end
@interface MTProxyConnectivity : NSObject
+ (MTSignal *)pingProxyWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId settings:(MTSocksProxySettings *)settings;
@end
@@ -0,0 +1,19 @@
#import <Foundation/Foundation.h>
@interface MTQueue : NSObject
- (instancetype)initWithName:(const char *)name;
+ (MTQueue *)mainQueue;
+ (MTQueue *)concurrentDefaultQueue;
+ (MTQueue *)concurrentLowQueue;
- (dispatch_queue_t)nativeQueue;
- (bool)isCurrentQueue;
- (void)dispatchOnQueue:(dispatch_block_t)block;
- (void)dispatchOnQueue:(dispatch_block_t)block synchronous:(bool)synchronous;
@end
@@ -0,0 +1,47 @@
#import <Foundation/Foundation.h>
@class MTRequestContext;
@class MTRequestErrorContext;
@class MTRpcError;
@interface MTRequestResponseInfo : NSObject
@property (nonatomic, readonly) int32_t networkType;
@property (nonatomic, readonly) double timestamp;
@property (nonatomic, readonly) double duration;
- (instancetype)initWithNetworkType:(int32_t)networkType timestamp:(double)timestamp duration:(double)duration;
@end
@interface MTRequest : NSObject
@property (nonatomic, strong, readonly) id internalId;
@property (nonatomic, strong, readonly) NSData *payload;
@property (nonatomic, strong, readonly) id metadata;
@property (nonatomic, strong, readonly) id shortMetadata;
@property (nonatomic, strong, readonly) id (^responseParser)(NSData *);
@property (nonatomic, strong) NSArray *decorators;
@property (nonatomic) int32_t transactionResetStateVersion;
@property (nonatomic, strong) MTRequestContext *requestContext;
@property (nonatomic, strong) MTRequestErrorContext *errorContext;
@property (nonatomic) bool hasHighPriority;
@property (nonatomic) bool dependsOnPasswordEntry;
@property (nonatomic) bool passthroughPasswordEntryError;
@property (nonatomic) bool needsTimeoutTimer;
@property (nonatomic) int32_t expectedResponseSize;
@property (nonatomic, copy) void (^completed)(id result, MTRequestResponseInfo *info, MTRpcError *error);
@property (nonatomic, copy) void (^progressUpdated)(float progress, NSUInteger packetLength);
@property (nonatomic, copy) void (^acknowledgementReceived)();
@property (nonatomic, copy) bool (^shouldContinueExecutionWithErrorContext)(MTRequestErrorContext *errorContext);
@property (nonatomic, copy) bool (^shouldDependOnRequest)(MTRequest *anotherRequest);
- (void)setPayload:(NSData *)payload metadata:(id)metadata shortMetadata:(id)shortMetadata responseParser:(id (^)(NSData *))responseParser;
@end
@@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
@interface MTRequestContext : NSObject
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t messageSeqNo;
@property (nonatomic) bool waitingForMessageId;
@property (nonatomic, strong) id transactionId;
@property (nonatomic) int32_t quickAckId;
@property (nonatomic) bool delivered;
@property (nonatomic) int64_t responseMessageId;
@property (nonatomic) bool willInitializeApi;
@property (nonatomic) double sentTimestamp;
- (instancetype)initWithMessageId:(int64_t)messageId messageSeqNo:(int32_t)messageSeqNo transactionId:(id)transactionId quickAckId:(int32_t)quickAckId;
@end
@@ -0,0 +1,41 @@
#import <Foundation/Foundation.h>
@protocol MTDisposable;
@interface MTRequestPendingVerificationData : NSObject
@property (nonatomic, strong, readonly) NSString *nonce;
@property (nonatomic, strong) NSString *secret;
@property (nonatomic) bool isResolved;
@property (nonatomic, strong) id<MTDisposable> disposable;
- (instancetype)initWithNonce:(NSString *)nonce;
@end
@interface MTRequestPendingRecaptchaVerificationData : NSObject
@property (nonatomic, strong, readonly) NSString *siteKey;
@property (nonatomic, strong) NSString *token;
@property (nonatomic) bool isResolved;
@property (nonatomic, strong) id<MTDisposable> disposable;
- (instancetype)initWithSiteKey:(NSString *)siteKey;
@end
@interface MTRequestErrorContext : NSObject
@property (nonatomic) CFAbsoluteTime minimalExecuteTime;
@property (nonatomic) NSUInteger internalServerErrorCount;
@property (nonatomic) NSUInteger floodWaitSeconds;
@property (nonatomic, strong) NSString *floodWaitErrorText;
@property (nonatomic) bool waitingForTokenExport;
@property (nonatomic, strong) id waitingForRequestToComplete;
@property (nonatomic, strong) MTRequestPendingVerificationData *pendingVerificationData;
@property (nonatomic, strong) MTRequestPendingRecaptchaVerificationData *pendingRecaptchaVerificationData;
@end
@@ -0,0 +1,37 @@
#import <MtProtoKit/MTMessageService.h>
@class MTContext;
@class MTRequest;
@class MTApiEnvironment;
@class MTRequestMessageService;
@protocol MTRequestMessageServiceDelegate <NSObject>
@optional
- (void)requestMessageServiceAuthorizationRequired:(MTRequestMessageService *)requestMessageService;
- (void)requestMessageServiceDidCompleteAllRequests:(MTRequestMessageService *)requestMessageService;
@end
@interface MTRequestMessageService : NSObject <MTMessageService>
@property (nonatomic, weak) id<MTRequestMessageServiceDelegate> delegate;
@property (nonatomic, strong) MTApiEnvironment *apiEnvironment;
@property (nonatomic) bool forceBackgroundRequests;
@property (nonatomic, copy) void (^didReceiveSoftAuthResetError)(void);
- (instancetype)initWithContext:(MTContext *)context;
- (void)addRequest:(MTRequest *)request;
- (void)removeRequestByInternalId:(id)internalId;
- (void)removeRequestByInternalId:(id)internalId askForReconnectionOnDrop:(bool)askForReconnectionOnDrop;
- (void)requestCount:(void (^)(NSUInteger requestCount))completion;
@end
@@ -0,0 +1,22 @@
#import <MtProtoKit/MTMessageService.h>
@class MTResendMessageService;
@protocol MTResendMessageServiceDelegate <NSObject>
@optional
- (void)resendMessageServiceCompleted:(MTResendMessageService *)resendService;
@end
@interface MTResendMessageService : NSObject <MTMessageService>
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, weak) id<MTResendMessageServiceDelegate> delegate;
- (instancetype)initWithMessageId:(int64_t)messageId;
@end
@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
@interface MTRpcError : NSObject
@property (nonatomic, readonly) int32_t errorCode;
@property (nonatomic, strong, readonly) NSString *errorDescription;
- (instancetype)initWithErrorCode:(int32_t)errorCode errorDescription:(NSString *)errorDescription;
@end
@@ -0,0 +1,25 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTExportedAuthorizationData.h>
#import <MtProtoKit/MTDatacenterAddressListData.h>
#import <MtProtoKit/MTDatacenterVerificationData.h>
typedef MTExportedAuthorizationData *(^MTExportAuthorizationResponseParser)(NSData *);
typedef MTDatacenterAddressListData *(^MTRequestDatacenterAddressListParser)(NSData *);
typedef MTDatacenterVerificationData *(^MTDatacenterVerificationDataParser)(NSData *);
typedef id (^MTRequestNoopParser)(NSData *);
@protocol MTSerialization <NSObject>
- (NSUInteger)currentLayer;
- (id)parseMessage:(NSData *)data;
- (MTExportAuthorizationResponseParser)exportAuthorization:(int32_t)datacenterId data:(__autoreleasing NSData **)data;
- (NSData *)importAuthorization:(int64_t)authId bytes:(NSData *)bytes;
- (MTRequestDatacenterAddressListParser)requestDatacenterAddressWithData:(__autoreleasing NSData **)data;
- (MTRequestNoopParser)requestNoop:(__autoreleasing NSData **)data;
@end
@@ -0,0 +1,37 @@
#import <Foundation/Foundation.h>
@class MTContext;
@interface MTSessionInfo : NSObject
@property (nonatomic) bool scheduledForCleanup;
@property (nonatomic) bool canBeDeleted;
- (instancetype)initWithRandomSessionIdAndContext:(MTContext *)context;
- (instancetype)initWithSessionId:(int64_t)sessionId context:(MTContext *)context;
- (int64_t)sessionId;
- (int64_t)generateClientMessageId:(bool *)monotonityViolated;
- (int64_t)generateServerMessageId;
- (int64_t)actualClientMessagId;
- (bool)messageProcessed:(int64_t)messageId;
- (void)setMessageProcessed:(int64_t)messageId;
- (bool)wasMessageSentOnce:(int64_t)messageId;
- (void)setMessageWasSentOnce:(int64_t)messageId;
- (void)scheduleMessageConfirmation:(int64_t)messageId size:(NSInteger)size;
- (NSArray *)scheduledMessageConfirmations;
- (bool)scheduledMessageConfirmationsExceedSize:(NSInteger)sizeLimit orCount:(NSUInteger)countLimit;
- (void)removeScheduledMessageConfirmationsWithIds:(NSArray *)messageIds;
- (void)assignTransactionId:(id)transactionId toScheduledMessageConfirmationsWithIds:(NSArray *)messageIds;
- (void)removeScheduledMessageConfirmationsWithTransactionIds:(NSArray *)transactionIds;
- (void)addContainerMessageIdMapping:(int64_t)containerMessageId childMessageIds:(NSArray *)childMessageIds;
- (NSArray *)messageIdsInContainer:(int64_t)containerMessageId;
- (NSArray *)messageIdsInContainersAfterMessageId:(int64_t)firstMessageId;
- (int32_t)takeSeqNo:(bool)messageIsMeaningful;
@end
@@ -0,0 +1,58 @@
#import <Foundation/Foundation.h>
#import "MTSubscriber.h"
@class MTQueue;
@interface MTSignal : NSObject
{
@public
id<MTDisposable> (^_generator)(MTSubscriber *);
}
- (instancetype)initWithGenerator:(id<MTDisposable> (^)(MTSubscriber *))generator;
- (id<MTDisposable>)startWithNext:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed;
- (id<MTDisposable>)startWithNextStrict:(void (^)(id next))next error:(void (^)(id error))error completed:(void (^)())completed file:(const char *)file line:(int)line;
- (id<MTDisposable>)startWithNext:(void (^)(id next))next;
- (id<MTDisposable>)startWithNextStrict:(void (^)(id next))next file:(const char *)file line:(int)line;
- (id<MTDisposable>)startWithNext:(void (^)(id next))next completed:(void (^)())completed;
- (id<MTDisposable>)startWithNextStrict:(void (^)(id next))next completed:(void (^)())completed file:(const char *)file line:(int)line;
+ (MTSignal *)single:(id)next;
+ (MTSignal *)fail:(id)error;
+ (MTSignal *)never;
+ (MTSignal *)complete;
- (MTSignal *)then:(MTSignal *)signal;
- (MTSignal *)delay:(NSTimeInterval)seconds onQueue:(MTQueue *)queue;
- (MTSignal *)timeout:(NSTimeInterval)seconds onQueue:(MTQueue *)queue orSignal:(MTSignal *)signal;
- (MTSignal *)catch:(MTSignal *(^)(id error))f;
+ (MTSignal *)mergeSignals:(NSArray *)signals;
+ (MTSignal *)combineSignals:(NSArray *)signals;
- (MTSignal *)restart;
- (MTSignal *)take:(NSUInteger)count;
- (MTSignal *)switchToLatest;
- (MTSignal *)map:(id (^)(id))f;
- (MTSignal *)filter:(bool (^)(id))f;
- (MTSignal *)mapToSignal:(MTSignal *(^)(id))f;
- (MTSignal *)onDispose:(void (^)())f;
- (MTSignal *)deliverOn:(MTQueue *)queue;
- (MTSignal *)startOn:(MTQueue *)queue;
- (MTSignal *)takeLast;
- (MTSignal *)reduceLeft:(id)value with:(id (^)(id, id))f;
@end
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#import "MTDisposable.h"
@interface MTSubscriber : NSObject <MTDisposable>
{
}
- (instancetype)initWithNext:(void (^)(id))next error:(void (^)(id))error completed:(void (^)())completed;
- (void)_assignDisposable:(id<MTDisposable>)disposable;
- (void)_markTerminatedWithoutDisposal;
- (void)putNext:(id)next;
- (void)putError:(id)error;
- (void)putCompletion;
@end
@@ -0,0 +1,5 @@
#import <MtProtoKit/MTTransport.h>
@interface MTTcpTransport : MTTransport
@end
@@ -0,0 +1,18 @@
#ifndef MtProtoKit_MTTime_h
#define MtProtoKit_MTTime_h
#ifdef __cplusplus
extern "C" {
#endif
#import <Foundation/Foundation.h>
CFAbsoluteTime MTAbsoluteSystemTime();
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
@interface MTTimeFixContext : NSObject
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t messageSeqNo;
@property (nonatomic, strong, readonly) id transactionId;
@property (nonatomic, readonly) CFAbsoluteTime timeFixAbsoluteStartTime;
- (instancetype)initWithMessageId:(int64_t)messageId messageSeqNo:(int32_t)messageSeqNo transactionId:(id)transactionId timeFixAbsoluteStartTime:(CFAbsoluteTime)timeFixAbsoluteStartTime;
@end
@@ -0,0 +1,18 @@
#import <MtProtoKit/MTMessageService.h>
@class MTTimeSyncMessageService;
@protocol MTTimeSyncMessageServiceDelegate <NSObject>
@optional
- (void)timeSyncServiceCompleted:(MTTimeSyncMessageService *)timeSyncService timeDifference:(NSTimeInterval)timeDifference saltList:(NSArray *)saltList;
@end
@interface MTTimeSyncMessageService : NSObject <MTMessageService>
@property (nonatomic, weak) id<MTTimeSyncMessageServiceDelegate> delegate;
@end
@@ -0,0 +1,17 @@
#import <Foundation/Foundation.h>
@interface MTTimer : NSObject
@property (nonatomic) NSTimeInterval timeoutDate;
- (id)initWithTimeout:(NSTimeInterval)timeout repeat:(bool)repeat completion:(dispatch_block_t)completion queue:(dispatch_queue_t)queue;
- (void)start;
- (void)fireAndInvalidate;
- (void)invalidate;
- (bool)isScheduled;
- (void)resetTimeout:(NSTimeInterval)timeout;
- (NSTimeInterval)remainingTime;
@end
@@ -0,0 +1,69 @@
#import <Foundation/Foundation.h>
@class MTContext;
@class MTTransportScheme;
@class MTTransport;
@class MTTransportTransaction;
@class MTOutgoingMessage;
@class MTIncomingMessage;
@class MTMessageTransaction;
@class MTNetworkUsageCalculationInfo;
@class MTSocksProxySettings;
#import <MtProtoKit/MTMessageService.h>
@protocol MTTransportDelegate <NSObject>
@optional
- (void)transportNetworkAvailabilityChanged:(MTTransport * _Nonnull)transport isNetworkAvailable:(bool)isNetworkAvailable;
- (void)transportConnectionStateChanged:(MTTransport * _Nonnull)transport isConnected:(bool)isConnected proxySettings:(MTSocksProxySettings * _Nullable)proxySettings;
- (void)transportConnectionFailed:(MTTransport * _Nonnull)transport scheme:(MTTransportScheme * _Nonnull)scheme;
- (void)transportConnectionContextUpdateStateChanged:(MTTransport * _Nonnull)transport isUpdatingConnectionContext:(bool)isUpdatingConnectionContext;
- (void)transportConnectionProblemsStatusChanged:(MTTransport * _Nonnull)transport scheme:(MTTransportScheme * _Nonnull)scheme hasConnectionProblems:(bool)hasConnectionProblems isProbablyHttp:(bool)isProbablyHttp;
- (void)transportReadyForTransaction:(MTTransport * _Nonnull)transport scheme:(MTTransportScheme * _Nonnull)scheme transportSpecificTransaction:(MTMessageTransaction * _Nonnull)transportSpecificTransaction forceConfirmations:(bool)forceConfirmations transactionReady:(void (^ _Nonnull)(NSArray * _Nonnull))transactionReady;
- (void)transportHasIncomingData:(MTTransport * _Nonnull)transport scheme:(MTTransportScheme * _Nonnull)scheme networkType:(int32_t)networkType data:(NSData * _Nonnull)data transactionId:(id _Nonnull)transactionId requestTransactionAfterProcessing:(bool)requestTransactionAfterProcessing decodeResult:(void (^ _Nonnull)(id _Nonnull transactionId, bool success))decodeResult;
- (void)transportTransactionsMayHaveFailed:(MTTransport * _Nonnull)transport transactionIds:(NSArray * _Nonnull)transactionIds;
- (void)transportReceivedQuickAck:(MTTransport * _Nonnull)transport quickAckId:(int32_t)quickAckId;
- (void)transportDecodeProgressToken:(MTTransport * _Nonnull)transport scheme:(MTTransportScheme * _Nonnull)scheme data:(NSData * _Nonnull)data token:(int64_t)token completion:(void (^ _Nonnull)(int64_t token, id _Nonnull progressToken))completion;
- (void)transportUpdatedDataReceiveProgress:(MTTransport * _Nonnull)transport progressToken:(id _Nonnull)progressToken packetLength:(NSInteger)packetLength progress:(float)progress;
- (void)transportActivityUpdated:(MTTransport * _Nonnull)transport;
@end
@interface MTTransport : NSObject <MTMessageService>
@property (nonatomic, weak) id<MTTransportDelegate> _Nullable delegate;
@property (nonatomic, strong, readonly) MTContext * _Nullable context;
@property (nonatomic, readonly) NSInteger datacenterId;
@property (nonatomic, strong, readonly) MTSocksProxySettings * _Nullable proxySettings;
@property (nonatomic) bool simultaneousTransactionsEnabled;
@property (nonatomic) bool reportTransportConnectionContextUpdateStates;
@property (nonatomic, strong) NSString * _Nullable (^ _Nullable getLogPrefix)();
- (instancetype _Nonnull)initWithDelegate:(id<MTTransportDelegate> _Nullable)delegate context:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings * _Null_unspecified)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo * _Nullable)usageCalculationInfo getLogPrefix:(NSString * _Nullable (^ _Nullable)())getLogPrefix;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo * _Null_unspecified)usageCalculationInfo;
- (bool)needsParityCorrection;
- (void)reset;
- (void)stop;
- (void)updateConnectionState;
- (void)setDelegateNeedsTransaction;
- (void)_processIncomingData:(NSData * _Nonnull)data scheme:(MTTransportScheme * _Nonnull)scheme networkType:(int32_t)networkType transactionId:(id _Nonnull)transactionId requestTransactionAfterProcessing:(bool)requestTransactionAfterProcessing decodeResult:(void (^ _Nonnull)(id _Nonnull transactionId, bool success))decodeResult;
- (void)_networkAvailabilityChanged:(bool)networkAvailable;
- (void)activeTransactionIds:(void (^ _Nonnull)(NSArray * _Nonnull activeTransactionId))completion;
- (void)updateSchemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes;
- (void)simulateDisconnection;
@end
@@ -0,0 +1,23 @@
#import <Foundation/Foundation.h>
@class MTContext;
@class MTTransport;
@class MTDatacenterAddress;
@protocol MTTransportDelegate;
@class MTNetworkUsageCalculationInfo;
@interface MTTransportScheme : NSObject <NSCoding>
@property (nonatomic, strong, readonly) Class _Nonnull transportClass;
@property (nonatomic, strong, readonly) MTDatacenterAddress * _Nonnull address;
@property (nonatomic, readonly) bool media;
- (instancetype _Nonnull)initWithTransportClass:(Class _Nonnull)transportClass address:(MTDatacenterAddress * _Nonnull)address media:(bool)media;
- (BOOL)isEqualToScheme:(MTTransportScheme * _Nonnull)other;
- (BOOL)isOptimal;
- (NSComparisonResult)compareToScheme:(MTTransportScheme * _Nonnull)other;
@end
@@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
@interface MTTransportTransaction : NSObject
@property (nonatomic, copy, readonly) void (^completion)(bool success, id transactionId);
@property (nonatomic, strong, readonly) NSData *payload;
@property (nonatomic, readonly) bool expectsDataInResponse;
@property (nonatomic, readonly) bool needsQuickAck;
- (instancetype)initWithPayload:(NSData *)payload completion:(void (^)(bool success, id transactionId))completion;
- (instancetype)initWithPayload:(NSData *)payload completion:(void (^)(bool success, id transactionId))completion needsQuickAck:(bool)needsQuickAck expectsDataInResponse:(bool)expectsDataInResponse;
@end
@@ -0,0 +1,63 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTAtomic.h>
#import <MtProtoKit/MTBackupAddressSignals.h>
#import <MtProtoKit/MTBag.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTDatacenterAddress.h>
#import <MtProtoKit/MTDatacenterAddressListData.h>
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTDatacenterAuthAction.h>
#import <MtProtoKit/MTDatacenterAuthMessageService.h>
#import <MtProtoKit/MTDatacenterSaltInfo.h>
#import <MtProtoKit/MTDatacenterTransferAuthAction.h>
#import <MtProtoKit/MTDatacenterVerificationData.h>
#import <MtProtoKit/MTDisposable.h>
#import <MtProtoKit/MTDropResponseContext.h>
#import <MtProtoKit/MTEncryption.h>
#import <MtProtoKit/MTExportedAuthorizationData.h>
#import <MtProtoKit/MTGzip.h>
#import <MtProtoKit/MTHttpRequestOperation.h>
#import <MtProtoKit/MTIncomingMessage.h>
#import <MtProtoKit/MTInputStream.h>
#import <MtProtoKit/MTInternalId.h>
#import <MtProtoKit/MTKeychain.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTMessageEncryptionKey.h>
#import <MtProtoKit/MTMessageService.h>
#import <MtProtoKit/MTMessageTransaction.h>
#import <MtProtoKit/MTNetworkAvailability.h>
#import <MtProtoKit/MTNetworkUsageCalculationInfo.h>
#import <MtProtoKit/MTNetworkUsageManager.h>
#import <MtProtoKit/MTOutgoingMessage.h>
#import <MtProtoKit/MTOutputStream.h>
#import <MtProtoKit/MTPreparedMessage.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTProxyConnectivity.h>
#import <MtProtoKit/MTQueue.h>
#import <MtProtoKit/MTRequest.h>
#import <MtProtoKit/MTRequestContext.h>
#import <MtProtoKit/MTRequestErrorContext.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTResendMessageService.h>
#import <MtProtoKit/MTRpcError.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTSessionInfo.h>
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTSubscriber.h>
#import <MtProtoKit/MTTcpTransport.h>
#import <MtProtoKit/MTTime.h>
#import <MtProtoKit/MTTimeFixContext.h>
#import <MtProtoKit/MTTimer.h>
#import <MtProtoKit/MTTimeSyncMessageService.h>
#import <MtProtoKit/MTTransport.h>
#import <MtProtoKit/MTTransportScheme.h>
#import <MtProtoKit/MTTransportTransaction.h>
#import <MtProtoKit/MTProtoInstance.h>
#import <MtProtoKit/MTProtoPersistenceInterface.h>
#import <MtProtoKit/MTProtoEngine.h>
#import <MtProtoKit/MTBindKeyMessageService.h>
#import <MtProtoKit/MTFileBasedKeychain.h>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
#import <Foundation/Foundation.h>
#import <MtProtoKit/MTEncryption.h>
void MyAesIgeEncrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);
void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);
void MyAesCbcDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv);
+327
View File
@@ -0,0 +1,327 @@
#import "MTAes.h"
#import <CommonCrypto/CommonCrypto.h>
# define AES_MAXNR 14
# define AES_BLOCK_SIZE 16
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
typedef struct {
unsigned long data[N_WORDS];
} aes_block_t;
/* XXX: probably some better way to do this */
#if defined(__i386__) || defined(__x86_64__)
# define UNALIGNED_MEMOPS_ARE_FAST 1
#else
# define UNALIGNED_MEMOPS_ARE_FAST 0
#endif
#if UNALIGNED_MEMOPS_ARE_FAST
# define load_block(d, s) (d) = *(const aes_block_t *)(s)
# define store_block(d, s) *(aes_block_t *)(d) = (s)
#else
# define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE)
# define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE)
#endif
void MyAesIgeEncrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
int len;
size_t n;
void const *inB;
void *outB;
unsigned char aesIv[AES_BLOCK_SIZE];
memcpy(aesIv, iv, AES_BLOCK_SIZE);
unsigned char ccIv[AES_BLOCK_SIZE];
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
0);
void *tmpInBytes = malloc(length);
len = length / AES_BLOCK_SIZE;
inB = inBytes;
outB = tmpInBytes;
aes_block_t *inp = (aes_block_t *)inB;
aes_block_t *outp = (aes_block_t *)outB;
for (n = 0; n < N_WORDS; ++n) {
outp->data[n] = inp->data[n];
}
--len;
inB += AES_BLOCK_SIZE;
outB += AES_BLOCK_SIZE;
void const *inBCC = inBytes;
aes_block_t const *iv3p = (aes_block_t *)ccIv;
if (len > 0) {
while (len) {
aes_block_t *inp = (aes_block_t *)inB;
aes_block_t *outp = (aes_block_t *)outB;
for (n = 0; n < N_WORDS; ++n) {
outp->data[n] = inp->data[n] ^ iv3p->data[n];
}
iv3p = inBCC;
--len;
inBCC += AES_BLOCK_SIZE;
inB += AES_BLOCK_SIZE;
outB += AES_BLOCK_SIZE;
}
}
size_t realOutLength = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 0, key, keyLength, aesIv, tmpInBytes, length, outBytes, length, &realOutLength);
free(tmpInBytes);
assert(result == kCCSuccess);
len = length / AES_BLOCK_SIZE;
aes_block_t const *ivp = inB;
aes_block_t *iv2p = (aes_block_t *)ccIv;
inB = inBytes;
outB = outBytes;
while (len) {
aes_block_t *inp = (aes_block_t *)inB;
aes_block_t *outp = (aes_block_t *)outB;
for (n = 0; n < N_WORDS; ++n) {
outp->data[n] ^= iv2p->data[n];
}
ivp = outp;
iv2p = inp;
--len;
inB += AES_BLOCK_SIZE;
outB += AES_BLOCK_SIZE;
}
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
}
void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
assert(length % 16 == 0);
assert(length >= 0);
unsigned char aesIv[AES_BLOCK_SIZE];
memcpy(aesIv, iv, AES_BLOCK_SIZE);
unsigned char ccIv[AES_BLOCK_SIZE];
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
0);
CCCryptorRef decryptor = NULL;
CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &decryptor);
if (decryptor != NULL) {
int len;
size_t n;
len = length / AES_BLOCK_SIZE;
aes_block_t *ivp = (aes_block_t *)(aesIv);
aes_block_t *iv2p = (aes_block_t *)(ccIv);
while (len) {
aes_block_t tmp;
aes_block_t *inp = (aes_block_t *)inBytes;
aes_block_t *outp = (aes_block_t *)outBytes;
for (n = 0; n < N_WORDS; ++n)
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
size_t dataOutMoved = 0;
CCCryptorStatus result = CCCryptorUpdate(decryptor, &tmp, AES_BLOCK_SIZE, outBytes, AES_BLOCK_SIZE, &dataOutMoved);
assert(result == kCCSuccess);
assert(dataOutMoved == AES_BLOCK_SIZE);
for (n = 0; n < N_WORDS; ++n)
outp->data[n] ^= ivp->data[n];
ivp = inp;
iv2p = outp;
inBytes += AES_BLOCK_SIZE;
outBytes += AES_BLOCK_SIZE;
--len;
}
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
CCCryptorRelease(decryptor);
}
}
void MyAesCbcDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
size_t outLength = 0;
CCCryptorStatus status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, key, keyLength, iv, inBytes, length, outBytes, length, &outLength);
assert(status == kCCSuccess);
assert(outLength == length);
}
static void ctr128_inc(unsigned char *counter)
{
uint32_t n = 16, c = 1;
do {
--n;
c += counter[n];
counter[n] = (uint8_t)c;
c >>= 8;
} while (n);
}
static void ctr128_inc_aligned(unsigned char *counter)
{
size_t *data, c, d, n;
const union {
long one;
char little;
} is_endian = {
1
};
if (is_endian.little || ((size_t)counter % sizeof(size_t)) != 0) {
ctr128_inc(counter);
return;
}
data = (size_t *)counter;
c = 1;
n = 16 / sizeof(size_t);
do {
--n;
d = data[n] += c;
/* did addition carry? */
c = ((d - c) ^ d) >> (sizeof(size_t) * 8 - 1);
} while (n);
}
@interface MTAesCtr () {
CCCryptorRef _cryptor;
unsigned char _ivec[16] __attribute__((aligned(16)));
unsigned int _num;
unsigned char _ecount[16] __attribute__((aligned(16)));
}
@end
@implementation MTAesCtr
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv decrypt:(bool)decrypt {
self = [super init];
if (self != nil) {
_num = 0;
memset(_ecount, 0, 16);
memcpy(_ivec, iv, 16);
CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &_cryptor);
}
return self;
}
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv ecount:(void *)ecount num:(uint32_t)num {
self = [super init];
if (self != nil) {
_num = num;
memcpy(_ecount, ecount, 16);
memcpy(_ivec, iv, 16);
CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &_cryptor);
}
return self;
}
- (void)dealloc {
if (_cryptor) {
CCCryptorRelease(_cryptor);
}
}
- (uint32_t)num {
return _num;
}
- (void *)ecount {
return _ecount;
}
- (void)getIv:(void *)iv {
memcpy(iv, _ivec, 16);
}
- (void)encryptIn:(const unsigned char *)in out:(unsigned char *)out len:(size_t)len {
unsigned int n;
size_t l = 0;
assert(in);
assert(out);
assert(_num < 16);
n = _num;
if (16 % sizeof(size_t) == 0) { /* always true actually */
do {
while (n && len) {
*(out++) = *(in++) ^ _ecount[n];
--len;
n = (n + 1) % 16;
}
if (((size_t)in|(size_t)out|(size_t)_ivec)%sizeof(size_t) != 0)
break;
while (len >= 16) {
size_t dataOutMoved;
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
ctr128_inc_aligned(_ivec);
for (n = 0; n < 16; n += sizeof(size_t)) {
*(size_t *)(out + n) =
*(size_t *)(in + n) ^ *(size_t *)(_ecount + n);
}
len -= 16;
out += 16;
in += 16;
n = 0;
}
if (len) {
size_t dataOutMoved;
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
ctr128_inc_aligned(_ivec);
while (len--) {
out[n] = in[n] ^ _ecount[n];
++n;
}
}
_num = n;
return;
} while (0);
}
/* the rest would be commonly eliminated by x86* compiler */
while (l < len) {
if (n == 0) {
size_t dataOutMoved;
CCCryptorUpdate(_cryptor, _ivec, 16, _ecount, 16, &dataOutMoved);
ctr128_inc(_ivec);
}
out[l] = in[l] ^ _ecount[n];
++l;
n = (n + 1) % 16;
}
_num = n;
}
@end
@@ -0,0 +1,897 @@
#import <MtProtoKit/MTApiEnvironment.h>
#if TARGET_OS_IPHONE
# import <UIKit/UIKit.h>
#else
#endif
#include <sys/sysctl.h>
#import <CommonCrypto/CommonDigest.h>
static NSData * _Nullable parseHexString(NSString * _Nonnull hex) {
if ([hex length] % 2 != 0) {
return nil;
}
char buf[3];
buf[2] = '\0';
uint8_t *bytes = (uint8_t *)malloc(hex.length / 2);
uint8_t *bp = bytes;
for (CFIndex i = 0; i < [hex length]; i += 2) {
buf[0] = [hex characterAtIndex:i];
buf[1] = [hex characterAtIndex:i+1];
char *b2 = NULL;
*bp++ = strtol(buf, &b2, 16);
if (b2 != buf + 2) {
return nil;
}
}
return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
}
static NSString * _Nonnull dataToHexString(NSData * _Nonnull data) {
const unsigned char *dataBuffer = (const unsigned char *)[data bytes];
if (dataBuffer == NULL) {
return @"";
}
NSUInteger dataLength = [data length];
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for (int i = 0; i < (int)dataLength; ++i) {
[hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
}
return hexString;
}
static NSData *base64_decode(NSString *str) {
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
return data;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [[NSData alloc] initWithBase64Encoding:[str stringByReplacingOccurrencesOfString:@"[^A-Za-z0-9+/=]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [str length])]];
#pragma clang diagnostic pop
}
}
@implementation MTProxySecret
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret {
self = [super init];
if (self != nil) {
_secret = secret;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self != nil) {
_secret = [aDecoder decodeObjectForKey:@"secret"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_secret forKey:@"secret"];
}
+ (MTProxySecret * _Nullable)parse:(NSString * _Nonnull)string {
NSData *hexData = parseHexString(string);
if (hexData == nil) {
NSString *finalString = @"";
finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]];
finalString = [finalString stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
finalString = [finalString stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
while (finalString.length % 4 != 0) {
finalString = [finalString stringByAppendingString:@"="];
}
hexData = base64_decode(finalString);
}
if (hexData != nil) {
return [self parseData:hexData];
} else {
return nil;
}
}
+ (MTProxySecret * _Nullable)parseData:(NSData * _Nonnull)data {
if (data == nil || data.length < 16) {
return nil;
}
uint8_t firstByte = 0;
[data getBytes:&firstByte length:1];
if (data.length == 16) {
return [[MTProxySecretType0 alloc] initWithSecret:data];
} else if (data.length == 17) {
if (firstByte == 0xdd) {
return [[MTProxySecretType1 alloc] initWithSecret:[data subdataWithRange:NSMakeRange(1, 16)]];
} else {
return nil;
}
} else if (data.length >= 18 && firstByte == 0xee) {
NSString *domain = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(1 + 16, data.length - (1 + 16))] encoding:NSUTF8StringEncoding];
if (domain == nil) {
return nil;
}
return [[MTProxySecretType2 alloc] initWithSecret:[data subdataWithRange:NSMakeRange(1, 16)] domain:domain];
} else {
return nil;
}
}
- (NSData * _Nonnull)serialize {
assert(false);
return nil;
}
- (NSString * _Nonnull)serializeToString {
assert(false);
return nil;
}
- (NSString *)description {
return dataToHexString([self serialize]);
}
@end
@implementation MTProxySecretType0
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret {
self = [super initWithSecret:secret];
if (self != nil) {
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self != nil) {
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
}
- (NSData * _Nonnull)serialize {
return self.secret;
}
- (NSString * _Nonnull)serializeToString {
return dataToHexString(self.serialize);
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MTProxySecretType0 class]]) {
return false;
}
MTProxySecretType0 *other = object;
if (![self.secret isEqual:other.secret]) {
return false;
}
return true;
}
@end
@implementation MTProxySecretType1
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret {
self = [super initWithSecret:secret];
if (self != nil) {
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self != nil) {
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
}
- (NSData * _Nonnull)serialize {
NSMutableData *data = [[NSMutableData alloc] init];
uint8_t marker = 0xdd;
[data appendBytes:&marker length:1];
[data appendData:self.secret];
return data;
}
- (NSString * _Nonnull)serializeToString {
return dataToHexString(self.serialize);
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MTProxySecretType1 class]]) {
return false;
}
MTProxySecretType1 *other = object;
if (![self.secret isEqual:other.secret]) {
return false;
}
return true;
}
@end
@implementation MTProxySecretType2
- (instancetype _Nullable)initWithSecret:(NSData * _Nonnull)secret domain:(NSString * _Nonnull)domain {
self = [super initWithSecret:secret];
if (self != nil) {
_domain = domain;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self != nil) {
_domain = [aDecoder decodeObjectForKey:@"domain"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_domain forKey:@"domain"];
}
- (NSData * _Nonnull)serialize {
NSMutableData *data = [[NSMutableData alloc] init];
uint8_t marker = 0xee;
[data appendBytes:&marker length:1];
[data appendData:self.secret];
[data appendData:[_domain dataUsingEncoding:NSUTF8StringEncoding]];
return data;
}
- (NSString * _Nonnull)serializeToString {
NSData *data = [self serialize];
if ([data respondsToSelector:@selector(base64EncodedDataWithOptions:)]) {
return [[data base64EncodedStringWithOptions:kNilOptions] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [self.serialize base64Encoding];
#pragma clang diagnostic pop
}
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MTProxySecretType2 class]]) {
return false;
}
MTProxySecretType2 *other = object;
if (![self.secret isEqual:other.secret]) {
return false;
}
if (![self.domain isEqual:other.domain]) {
return false;
}
return true;
}
@end
@implementation MTSocksProxySettings
- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password secret:(NSData *)secret {
self = [super init];
if (self != nil) {
_ip = ip;
_port = port;
_username = username;
_password = password;
_secret = secret;
}
return self;
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MTSocksProxySettings class]]) {
return false;
}
MTSocksProxySettings *other = object;
if ((other->_ip != nil) != (_ip != nil) || (_ip != nil && ![_ip isEqual:other->_ip])) {
return false;
}
if (other->_port != _port) {
return false;
}
if ((other->_username != nil) != (_username != nil) || (_username != nil && ![_username isEqual:other->_username])) {
return false;
}
if ((other->_password != nil) != (_password != nil) || (_password != nil && ![_password isEqual:other->_password])) {
return false;
}
if ((other->_secret != nil) != (_secret != nil) || (_secret != nil && ![_secret isEqual:other->_secret])) {
return false;
}
return true;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@:%d+%@+%@+%@", _ip, (int)_port, _username, _password, [_secret description]];
}
@end
@implementation MTNetworkSettings
- (instancetype)initWithReducedBackupDiscoveryTimeout:(bool)reducedBackupDiscoveryTimeout {
self = [super init];
if (self != nil) {
_reducedBackupDiscoveryTimeout = reducedBackupDiscoveryTimeout;
}
return self;
}
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MTNetworkSettings class]]) {
return false;
}
MTNetworkSettings *other = object;
if (_reducedBackupDiscoveryTimeout != other->_reducedBackupDiscoveryTimeout) {
return false;
}
return true;
}
@end
@implementation MTApiEnvironment
-(instancetype)init {
self = [self initWithDeviceModelName:nil];
if (self != nil)
{
}
return self;
}
-(id _Nonnull)initWithDeviceModelName:(NSString * _Nullable)deviceModelName {
self = [super init];
if (self != nil)
{
if (deviceModelName != nil) {
_deviceModel = deviceModelName;
} else {
_deviceModel = [self platformString];
}
_deviceModelName = deviceModelName;
#if TARGET_OS_IPHONE
_systemVersion = [[UIDevice currentDevice] systemVersion];
#else
NSProcessInfo *pInfo = [NSProcessInfo processInfo];
_systemVersion = [[[pInfo operatingSystemVersionString] componentsSeparatedByString:@" "] objectAtIndex:1];
#endif
NSString *suffix = @"";
#if TARGET_OS_OSX
NSString *value = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"SOURCE"];
if (value != nil) {
suffix = [NSString stringWithFormat:@"%@", value];
}
#endif
//SOURCE
NSString *versionString = [[NSString alloc] initWithFormat:@"%@ (%@) %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"], suffix];
_appVersion = versionString;
_systemLangCode = [[NSLocale preferredLanguages] objectAtIndex:0];
#if TARGET_OS_OSX
_langPack = @"macos";
#else
_langPack = @"ios";
#endif
_langPackCode = @"";
[self _updateApiInitializationHash];
}
return self;
}
- (void)_updateApiInitializationHash {
_apiInitializationHash = [[NSString alloc] initWithFormat:@"apiId=%" PRId32 "&deviceModel=%@&systemVersion=%@&appVersion=%@&langCode=%@&layer=%@&langPack=%@&langPackCode=%@&proxy=%@&systemCode=%@", _apiId, _deviceModel, _systemVersion, _appVersion, _systemLangCode, _layer, _langPack, _langPackCode, _socksProxySettings, _systemCode];
}
- (void)setLayer:(NSNumber *)layer {
_layer = layer;
[self _updateApiInitializationHash];
}
- (void)setAppVersion:(NSString *)appVersion {
_appVersion = appVersion;
[self _updateApiInitializationHash];
}
- (void)setLangPack:(NSString *)langPack {
_langPack = langPack;
[self _updateApiInitializationHash];
}
- (void)setLangPackCode:(NSString *)langPackCode {
_langPackCode = langPackCode;
[self _updateApiInitializationHash];
}
- (NSString *)platformString
{
#if TARGET_OS_IPHONE
NSString *platform = [self platform];
if ([platform isEqualToString:@"iPhone1,1"])
return @"iPhone";
if ([platform isEqualToString:@"iPhone1,2"])
return @"iPhone 3G";
if ([platform isEqualToString:@"iPhone2,1"])
return @"iPhone 3GS";
if ([platform hasPrefix:@"iPhone3"])
return @"iPhone 4";
if ([platform hasPrefix:@"iPhone4"])
return @"iPhone 4S";
if ([platform isEqualToString:@"iPhone5,1"] ||
[platform isEqualToString:@"iPhone5,2"])
return @"iPhone 5";
if ([platform isEqualToString:@"iPhone5,3"] ||
[platform isEqualToString:@"iPhone5,4"])
return @"iPhone 5C";
if ([platform hasPrefix:@"iPhone6"])
return @"iPhone 5S";
if ([platform isEqualToString:@"iPhone7,1"])
return @"iPhone 6 Plus";
if ([platform isEqualToString:@"iPhone7,2"])
return @"iPhone 6";
if ([platform isEqualToString:@"iPhone8,1"])
return @"iPhone 6S";
if ([platform isEqualToString:@"iPhone8,2"])
return @"iPhone 6S Plus";
if ([platform isEqualToString:@"iPhone8,4"])
return @"iPhone SE";
if ([platform isEqualToString:@"iPhone9,1"] ||
[platform isEqualToString:@"iPhone9,3"])
return @"iPhone 7";
if ([platform isEqualToString:@"iPhone9,2"] ||
[platform isEqualToString:@"iPhone9,4"])
return @"iPhone 7 Plus";
if ([platform isEqualToString:@"iPhone10,1"] ||
[platform isEqualToString:@"iPhone10,4"])
return @"iPhone 8";
if ([platform isEqualToString:@"iPhone10,2"] ||
[platform isEqualToString:@"iPhone10,5"])
return @"iPhone 8 Plus";
if ([platform isEqualToString:@"iPhone10,3"] ||
[platform isEqualToString:@"iPhone10,6"])
return @"iPhone X";
if ([platform isEqualToString:@"iPhone11,2"])
return @"iPhone XS";
if ([platform isEqualToString:@"iPhone11,4"] ||
[platform isEqualToString:@"iPhone11,6"])
return @"iPhone XS Max";
if ([platform isEqualToString:@"iPhone11,8"])
return @"iPhone XR";
if ([platform isEqualToString:@"iPhone12,1"])
return @"iPhone 11";
if ([platform isEqualToString:@"iPhone12,3"])
return @"iPhone 11 Pro";
if ([platform isEqualToString:@"iPhone12,5"])
return @"iPhone 11 Pro Max";
if ([platform isEqualToString:@"iPhone12,8"])
return @"iPhone SE (2nd gen)";
if ([platform isEqualToString:@"iPhone13,1"])
return @"iPhone 12 mini";
if ([platform isEqualToString:@"iPhone13,2"])
return @"iPhone 12";
if ([platform isEqualToString:@"iPhone13,3"])
return @"iPhone 12 Pro";
if ([platform isEqualToString:@"iPhone13,4"])
return @"iPhone 12 Pro Max";
if ([platform isEqualToString:@"iPhone14,2"])
return @"iPhone 13 Pro";
if ([platform isEqualToString:@"iPhone14,3"])
return @"iPhone 13 Pro Max";
if ([platform isEqualToString:@"iPhone14,4"])
return @"iPhone 13 Mini";
if ([platform isEqualToString:@"iPhone14,5"])
return @"iPhone 13";
if ([platform isEqualToString:@"iPhone14,6"])
return @"iPhone SE (3rd gen)";
if ([platform isEqualToString:@"iPhone14,7"])
return @"iPhone 14";
if ([platform isEqualToString:@"iPhone14,8"])
return @"iPhone 14 Plus";
if ([platform isEqualToString:@"iPhone15,2"])
return @"iPhone 14 Pro";
if ([platform isEqualToString:@"iPhone15,3"])
return @"iPhone 14 Pro Max";
if ([platform isEqualToString:@"iPhone15,4"])
return @"iPhone 15";
if ([platform isEqualToString:@"iPhone15,5"])
return @"iPhone 15 Plus";
if ([platform isEqualToString:@"iPhone16,1"])
return @"iPhone 15 Pro";
if ([platform isEqualToString:@"iPhone16,2"])
return @"iPhone 15 Pro Max";
if ([platform isEqualToString:@"iPhone17,3"])
return @"iPhone 16";
if ([platform isEqualToString:@"iPhone17,4"])
return @"iPhone 16 Plus";
if ([platform isEqualToString:@"iPhone17,1"])
return @"iPhone 16 Pro";
if ([platform isEqualToString:@"iPhone17,2"])
return @"iPhone 16 Pro Max";
if ([platform isEqualToString:@"iPhone17,5"])
return @"iPhone 16e";
if ([platform isEqualToString:@"iPhone18,3"])
return @"iPhone 17";
if ([platform isEqualToString:@"iPhone18,1"])
return @"iPhone 17 Pro";
if ([platform isEqualToString:@"iPhone18,2"])
return @"iPhone 17 Pro Max";
if ([platform isEqualToString:@"iPhone18,4"])
return @"iPhone Air";
if ([platform hasPrefix:@"iPod1"])
return @"iPod touch 1G";
if ([platform hasPrefix:@"iPod2"])
return @"iPod touch 2G";
if ([platform hasPrefix:@"iPod3"])
return @"iPod touch 3G";
if ([platform hasPrefix:@"iPod4"])
return @"iPod touch 4G";
if ([platform hasPrefix:@"iPod5"])
return @"iPod touch 5G";
if ([platform hasPrefix:@"iPod7"])
return @"iPod touch 6G";
if ([platform hasPrefix:@"iPod9"])
return @"iPod touch 7G";
if ([platform isEqualToString:@"iPad2,5"] ||
[platform isEqualToString:@"iPad2,6"] ||
[platform isEqualToString:@"iPad2,7"])
return @"iPad mini";
if ([platform hasPrefix:@"iPad2"])
return @"iPad 2G";
if ([platform isEqualToString:@"iPad3,1"] ||
[platform isEqualToString:@"iPad3,2"] ||
[platform isEqualToString:@"iPad3,3"])
return @"iPad 3G";
if ([platform isEqualToString:@"iPad3,4"] ||
[platform isEqualToString:@"iPad3,5"] ||
[platform isEqualToString:@"iPad3,6"])
return @"iPad 3G";
if ([platform isEqualToString:@"iPad4,1"] ||
[platform isEqualToString:@"iPad4,2"])
return @"iPad Air";
if ([platform isEqualToString:@"iPad4,4"] ||
[platform isEqualToString:@"iPad4,5"] ||
[platform isEqualToString:@"iPad4,6"])
return @"iPad mini Retina";
if ([platform isEqualToString:@"iPad4,7"] ||
[platform isEqualToString:@"iPad4,8"] ||
[platform isEqualToString:@"iPad4,9"])
return @"iPad mini 3";
if ([platform isEqualToString:@"iPad5,1"] ||
[platform isEqualToString:@"iPad5,2"])
return @"iPad mini 4";
if ([platform isEqualToString:@"iPad5,3"] ||
[platform isEqualToString:@"iPad5,4"])
return @"iPad Air 2";
if ([platform isEqualToString:@"iPad6,3"] ||
[platform isEqualToString:@"iPad6,4"])
return @"iPad Pro 9.7 inch";
if ([platform isEqualToString:@"iPad6,7"] ||
[platform isEqualToString:@"iPad6,8"])
return @"iPad Pro 12.9 inch";
if ([platform isEqualToString:@"iPad6,11"] ||
[platform isEqualToString:@"iPad6,12"])
return @"iPad (2017)";
if ([platform isEqualToString:@"iPad7,1"] ||
[platform isEqualToString:@"iPad7,2"])
return @"iPad Pro (2nd gen)";
if ([platform isEqualToString:@"iPad7,3"] ||
[platform isEqualToString:@"iPad7,4"])
return @"iPad Pro 10.5 inch";
if ([platform isEqualToString:@"iPad7,5"] ||
[platform isEqualToString:@"iPad7,6"])
return @"iPad (6th gen)";
if ([platform isEqualToString:@"iPad7,11"] ||
[platform isEqualToString:@"iPad7,12"])
return @"iPad 10.2 inch (7th gen)";
if ([platform isEqualToString:@"iPad8,1"] ||
[platform isEqualToString:@"iPad8,2"] ||
[platform isEqualToString:@"iPad8,3"] ||
[platform isEqualToString:@"iPad8,4"])
return @"iPad Pro 11 inch";
if ([platform isEqualToString:@"iPad8,5"] ||
[platform isEqualToString:@"iPad8,6"] ||
[platform isEqualToString:@"iPad8,7"] ||
[platform isEqualToString:@"iPad8,8"])
return @"iPad Pro 12.9 inch (3rd gen)";
if ([platform isEqualToString:@"iPad8,9"] ||
[platform isEqualToString:@"iPad8,10"])
return @"iPad Pro 11 inch (2th gen)";
if ([platform isEqualToString:@"iPad8,11"] ||
[platform isEqualToString:@"iPad8,12"])
return @"iPad Pro 12.9 inch (4th gen)";
if ([platform isEqualToString:@"iPad11,1"] ||
[platform isEqualToString:@"iPad11,2"])
return @"iPad mini (5th gen)";
if ([platform isEqualToString:@"iPad11,3"] ||
[platform isEqualToString:@"iPad11,4"])
return @"iPad Air (3rd gen)";
if ([platform isEqualToString:@"iPad11,6"] ||
[platform isEqualToString:@"iPad11,7"])
return @"iPad (8th gen)";
if ([platform isEqualToString:@"iPad12,1"] ||
[platform isEqualToString:@"iPad12,2"])
return @"iPad (9th gen)";
if ([platform isEqualToString:@"iPad13,1"] ||
[platform isEqualToString:@"iPad13,2"])
return @"iPad Air (4th gen)";
if ([platform isEqualToString:@"iPad13,4"] ||
[platform isEqualToString:@"iPad13,5"] ||
[platform isEqualToString:@"iPad13,6"] ||
[platform isEqualToString:@"iPad13,7"])
return @"iPad Pro 11 inch (3th gen)";
if ([platform isEqualToString:@"iPad13,8"] ||
[platform isEqualToString:@"iPad13,9"] ||
[platform isEqualToString:@"iPad13,10"] ||
[platform isEqualToString:@"iPad13,11"])
return @"iPad Pro 12.9 inch (5th gen)";
if ([platform isEqualToString:@"iPad13,16"] ||
[platform isEqualToString:@"iPad13,17"])
return @"iPad Air (5th gen)";
if ([platform isEqualToString:@"iPad13,18"] ||
[platform isEqualToString:@"iPad13,19"])
return @"iPad (10th gen)";
if ([platform isEqualToString:@"iPad14,1"] ||
[platform isEqualToString:@"iPad14,2"])
return @"iPad mini (6th gen)";
if ([platform isEqualToString:@"iPad14,3"] ||
[platform isEqualToString:@"iPad14,4"])
return @"iPad Pro 11 inch (4th gen)";
if ([platform isEqualToString:@"iPad14,5"] ||
[platform isEqualToString:@"iPad14,6"])
return @"iPad Pro 12.9 inch (6th gen)";
if ([platform isEqualToString:@"iPad14,8"] ||
[platform isEqualToString:@"iPad14,9"])
return @"iPad Air (6th gen)";
if ([platform isEqualToString:@"iPad14,10"] ||
[platform isEqualToString:@"iPad14,11"])
return @"iPad Air (7th gen)";
if ([platform isEqualToString:@"iPad16,3"] ||
[platform isEqualToString:@"iPad16,4"])
return @"iPad Pro 11 inch (5th gen)";
if ([platform isEqualToString:@"iPad16,5"] ||
[platform isEqualToString:@"iPad16,6"])
return @"iPad Pro 12.9 inch (7th gen)";
if ([platform hasPrefix:@"iPhone"])
return @"Unknown iPhone";
if ([platform hasPrefix:@"iPod"])
return @"Unknown iPod";
if ([platform hasPrefix:@"iPad"])
return @"Unknown iPad";
if ([platform hasSuffix:@"86"] || [platform isEqual:@"x86_64"] || [platform isEqual:@"arm64"]) {
return @"iPhone Simulator";
}
#else
return [self macHWName];
#endif
return @"Unknown iOS device";
}
- (NSString *)macHWName {
size_t len = 0;
sysctlbyname("hw.model", NULL, &len, NULL, 0);
if (len) {
char *model = malloc(len*sizeof(char));
sysctlbyname("hw.model", model, &len, NULL, 0);
NSString *name = [[NSString alloc] initWithUTF8String:model];
free(model);
return name;
};
return @"macOS";
}
- (NSString *)getSysInfoByName:(char *)typeSpecifier
{
size_t size;
sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
char *answer = malloc(size);
sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
free(answer);
return results;
}
- (NSString *)platform
{
return [self getSysInfoByName:"hw.machine"];
}
- (MTApiEnvironment *)withUpdatedLangPackCode:(NSString *)langPackCode {
MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
result.apiId = self.apiId;
result.appVersion = self.appVersion;
result.layer = self.layer;
result.langPack = self.langPack;
result->_langPackCode = langPackCode;
result.disableUpdates = self.disableUpdates;
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
result.accessHostOverride = self.accessHostOverride;
result->_socksProxySettings = self.socksProxySettings;
result->_networkSettings = self.networkSettings;
result->_systemCode = self.systemCode;
[result _updateApiInitializationHash];
return result;
}
- (instancetype)copyWithZone:(NSZone *)__unused zone {
MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
result.apiId = self.apiId;
result.appVersion = self.appVersion;
result.layer = self.layer;
result.langPack = self.langPack;
result->_langPackCode = self.langPackCode;
result->_socksProxySettings = self.socksProxySettings;
result->_networkSettings = self.networkSettings;
result->_systemCode = self.systemCode;
result.disableUpdates = self.disableUpdates;
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
result.accessHostOverride = self.accessHostOverride;
[result _updateApiInitializationHash];
return result;
}
- (MTApiEnvironment *)withUpdatedSocksProxySettings:(MTSocksProxySettings *)socksProxySettings {
MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
result.apiId = self.apiId;
result.appVersion = self.appVersion;
result.layer = self.layer;
result.langPack = self.langPack;
result->_langPackCode = self.langPackCode;
result->_socksProxySettings = socksProxySettings;
result->_networkSettings = self.networkSettings;
result->_systemCode = self.systemCode;
result.disableUpdates = self.disableUpdates;
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
result.accessHostOverride = self.accessHostOverride;
[result _updateApiInitializationHash];
return result;
}
- (MTApiEnvironment *)withUpdatedNetworkSettings:(MTNetworkSettings *)networkSettings {
MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
result.apiId = self.apiId;
result.appVersion = self.appVersion;
result.layer = self.layer;
result.langPack = self.langPack;
result->_langPackCode = self.langPackCode;
result->_socksProxySettings = self.socksProxySettings;
result->_networkSettings = networkSettings;
result->_systemCode = self.systemCode;
result.disableUpdates = self.disableUpdates;
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
result.accessHostOverride = self.accessHostOverride;
[result _updateApiInitializationHash];
return result;
}
- (MTApiEnvironment *)withUpdatedSystemCode:(NSData *)systemCode {
MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
result.apiId = self.apiId;
result.appVersion = self.appVersion;
result.layer = self.layer;
result.langPack = self.langPack;
result->_langPackCode = self.langPackCode;
result->_socksProxySettings = self.socksProxySettings;
result->_networkSettings = self.networkSettings;
result->_systemCode = systemCode;
result.disableUpdates = self.disableUpdates;
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
result.accessHostOverride = self.accessHostOverride;
[result _updateApiInitializationHash];
return result;
}
@end
+64
View File
@@ -0,0 +1,64 @@
#import <MtProtoKit/MTAtomic.h>
#import <os/lock.h>
@interface MTAtomic ()
{
os_unfair_lock _lock;
id _value;
}
@end
@implementation MTAtomic
- (instancetype)initWithValue:(id)value
{
self = [super init];
if (self != nil)
{
_value = value;
}
return self;
}
- (id)swap:(id)newValue
{
id previousValue = nil;
os_unfair_lock_lock(&_lock);
previousValue = _value;
_value = newValue;
os_unfair_lock_unlock(&_lock);
return previousValue;
}
- (id)value
{
id previousValue = nil;
os_unfair_lock_lock(&_lock);
previousValue = _value;
os_unfair_lock_unlock(&_lock);
return previousValue;
}
- (id)modify:(id (^)(id))f
{
id newValue = nil;
os_unfair_lock_lock(&_lock);
newValue = f(_value);
_value = newValue;
os_unfair_lock_unlock(&_lock);
return newValue;
}
- (id)with:(id (^)(id))f
{
id result = nil;
os_unfair_lock_lock(&_lock);
result = f(_value);
os_unfair_lock_unlock(&_lock);
return result;
}
@end
@@ -0,0 +1,412 @@
#import <MtProtoKit/MTBackupAddressSignals.h>
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTAtomic.h>
#import <MtProtoKit/MTQueue.h>
#import <MtProtoKit/MTHttpRequestOperation.h>
#import <MtProtoKit/MTEncryption.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTRequest.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTDatacenterAddress.h>
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTKeychain.h>
@interface MTTemporaryKeychain : NSObject<MTKeychain> {
NSMutableDictionary<NSString *, id> *_dict;
}
@end
@implementation MTTemporaryKeychain
- (instancetype)init {
self = [super init];
if (self != nil) {
_dict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (NSString *)itemKeyForGroup:(NSString *)group key:(NSString *)key {
return [NSString stringWithFormat:@"%@:%@", group, key];
}
- (void)setObject:(id)object forKey:(NSString *)aKey group:(NSString *)group {
if (object == nil) {
return;
}
_dict[[self itemKeyForGroup:group key:aKey]] = object;
}
- (NSDictionary *)dictionaryForKey:(NSString *)aKey group:(NSString *)group {
id result = _dict[[self itemKeyForGroup:group key:aKey]];
if ([result isKindOfClass:[NSDictionary class]]) {
return result;
} else {
return nil;
}
}
- (NSNumber *)numberForKey:(NSString *)aKey group:(NSString *)group {
id result = _dict[[self itemKeyForGroup:group key:aKey]];
if ([result isKindOfClass:[NSNumber class]]) {
return result;
} else {
return nil;
}
}
- (void)removeObjectForKey:(NSString *)aKey group:(NSString *)group {
[_dict removeObjectForKey:[self itemKeyForGroup:group key:aKey]];
}
@end
static NSData *base64_decode(NSString *str) {
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];
return data;
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [[NSData alloc] initWithBase64Encoding:[str stringByReplacingOccurrencesOfString:@"[^A-Za-z0-9+/=]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, [str length])]];
#pragma clang diagnostic pop
}
}
@implementation MTBackupAddressSignals
+ (bool)checkIpData:(MTBackupDatacenterData *)data timestamp:(int32_t)timestamp source:(NSString *)source {
if (data.timestamp >= timestamp + 60 * 20 || data.expirationDate <= timestamp - 60 * 20) {
if (MTLogEnabled()) {
MTLog(@"[Backup address fetch: backup config from %@ validity interval %d ... %d does not include current %d]", source, data.timestamp, data.expirationDate, timestamp);
}
return false;
} else {
return true;
}
}
+ (MTSignal *)fetchBackupIpsResolveGoogle:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride {
NSArray *hosts = @[
@[@"dns.google.com", @""],
@[@"www.google.com", @"dns.google.com"],
];
id<EncryptionProvider> encryptionProvider = currentContext.encryptionProvider;
NSMutableArray *signals = [[NSMutableArray alloc] init];
for (NSArray *hostAndHostname in hosts) {
NSString *host = hostAndHostname[0];
NSString *hostName = hostAndHostname[1];
NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];
if ([hostName length] != 0) {
headers[@"Host"] = hostName;
}
NSString *apvHost = @"apv3.stel.com";
if (addressOverride != nil) {
apvHost = addressOverride;
}
MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16&random_padding=%@", host, isTesting ? @"tapv3.stel.com" : apvHost, makeRandomPadding()]] headers:headers] mapToSignal:^MTSignal *(MTHttpResponse *response) {
NSString *dateHeader = response.headers[@"Date"];
if ([dateHeader isKindOfClass:[NSString class]]) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[formatter setLocale:usLocale];
[formatter setDateFormat:@"EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"];
NSDate *date = [formatter dateFromString:dateHeader];
if (date != nil) {
double difference = [date timeIntervalSince1970] - [[NSDate date] timeIntervalSince1970];
[MTContext setFixedTimeDifference:(int32_t)difference];
}
}
NSData *data = response.data;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([dict respondsToSelector:@selector(objectForKey:)]) {
NSArray *answer = dict[@"Answer"];
NSMutableArray *strings = [[NSMutableArray alloc] init];
if ([answer respondsToSelector:@selector(objectAtIndex:)]) {
for (NSDictionary *value in answer) {
if ([value respondsToSelector:@selector(objectForKey:)]) {
NSString *part = value[@"data"];
if ([part respondsToSelector:@selector(characterAtIndex:)]) {
[strings addObject:part];
}
}
}
[strings sortUsingComparator:^NSComparisonResult(NSString *lhs, NSString *rhs) {
if (lhs.length > rhs.length) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}];
NSString *finalString = @"";
for (NSString *string in strings) {
finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]];
}
NSData *result = base64_decode(finalString);
NSMutableData *finalData = [[NSMutableData alloc] initWithData:result];
[finalData setLength:256];
MTBackupDatacenterData *datacenterData = MTIPDataDecode(encryptionProvider, finalData, phoneNumber);
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveGoogle"]) {
return [MTSignal single:datacenterData];
}
}
}
return [MTSignal complete];
}] catch:^MTSignal *(__unused id error) {
return [MTSignal complete];
}];
if (signals.count != 0) {
signal = [signal delay:signals.count onQueue:[[MTQueue alloc] init]];
}
[signals addObject:signal];
}
return [[MTSignal mergeSignals:signals] take:1];
}
static NSString *makeRandomPadding() {
char validCharacters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int maxIndex = sizeof(validCharacters) - 1;
int minPadding = 13;
int maxPadding = 128;
int padding = minPadding + arc4random_uniform(maxPadding - minPadding);
NSMutableData *result = [[NSMutableData alloc] initWithLength:padding];
for (NSUInteger i = 0; i < result.length; i++) {
int index = arc4random_uniform(maxIndex);
assert(index >= 0 && index < maxIndex);
((uint8_t *)(result.mutableBytes))[i] = validCharacters[index];
}
NSString *string = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
return string;
}
+ (MTSignal *)fetchBackupIpsResolveCloudflare:(bool)isTesting phoneNumber:(NSString *)phoneNumber currentContext:(MTContext *)currentContext addressOverride:(NSString *)addressOverride {
id<EncryptionProvider> encryptionProvider = currentContext.encryptionProvider;
NSArray *hosts = @[
@[@"mozilla.cloudflare-dns.com", @""],
];
NSMutableArray *signals = [[NSMutableArray alloc] init];
for (NSArray *hostAndHostname in hosts) {
NSString *host = hostAndHostname[0];
NSString *hostName = hostAndHostname[1];
NSMutableDictionary *headers = [[NSMutableDictionary alloc] init];
headers[@"accept"] = @"application/dns-json";
if ([hostName length] != 0) {
headers[@"Host"] = hostName;
}
NSString *apvHost = @"apv3.stel.com";
if (addressOverride != nil) {
apvHost = addressOverride;
}
MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/dns-query?name=%@&type=16&random_padding=%@", host, isTesting ? @"tapv3.stel.com" : apvHost, makeRandomPadding()]] headers:headers] mapToSignal:^MTSignal *(MTHttpResponse *response) {
NSString *dateHeader = response.headers[@"Date"];
if ([dateHeader isKindOfClass:[NSString class]]) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[formatter setLocale:usLocale];
[formatter setDateFormat:@"EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"];
NSDate *date = [formatter dateFromString:dateHeader];
if (date != nil) {
double difference = [date timeIntervalSince1970] - [[NSDate date] timeIntervalSince1970];
[MTContext setFixedTimeDifference:(int32_t)difference];
}
}
NSData *data = response.data;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([dict respondsToSelector:@selector(objectForKey:)]) {
NSArray *answer = dict[@"Answer"];
NSMutableArray *strings = [[NSMutableArray alloc] init];
if ([answer respondsToSelector:@selector(objectAtIndex:)]) {
for (NSDictionary *value in answer) {
if ([value respondsToSelector:@selector(objectForKey:)]) {
NSString *part = value[@"data"];
if ([part respondsToSelector:@selector(characterAtIndex:)]) {
[strings addObject:part];
}
}
}
[strings sortUsingComparator:^NSComparisonResult(NSString *lhs, NSString *rhs) {
if (lhs.length > rhs.length) {
return NSOrderedAscending;
} else {
return NSOrderedDescending;
}
}];
NSString *finalString = @"";
for (NSString *string in strings) {
finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]];
}
NSData *result = base64_decode(finalString);
NSMutableData *finalData = [[NSMutableData alloc] initWithData:result];
[finalData setLength:256];
MTBackupDatacenterData *datacenterData = MTIPDataDecode(encryptionProvider, finalData, phoneNumber);
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveCloudflare"]) {
return [MTSignal single:datacenterData];
}
}
}
return [MTSignal complete];
}] catch:^MTSignal *(__unused id error) {
return [MTSignal complete];
}];
if (signals.count != 0) {
signal = [signal delay:signals.count onQueue:[[MTQueue alloc] init]];
}
[signals addObject:signal];
}
return [[MTSignal mergeSignals:signals] take:1];
}
MTAtomic *sharedFetchConfigKeychains() {
static MTAtomic *value = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
value = [[MTAtomic alloc] initWithValue:[[NSMutableDictionary alloc] init]];
});
return value;
}
+ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext mainDatacenterId:(NSInteger)mainDatacenterId {
MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy];
apiEnvironment = [apiEnvironment withUpdatedSocksProxySettings:nil];
NSMutableDictionary *datacenterAddressOverrides = [[NSMutableDictionary alloc] init];
datacenterAddressOverrides[@(address.datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false secret:address.secret];
apiEnvironment.datacenterAddressOverrides = datacenterAddressOverrides;
apiEnvironment.apiId = currentContext.apiEnvironment.apiId;
apiEnvironment.layer = currentContext.apiEnvironment.layer;
apiEnvironment = [apiEnvironment withUpdatedLangPackCode:currentContext.apiEnvironment.langPackCode];
apiEnvironment.disableUpdates = true;
apiEnvironment.langPack = currentContext.apiEnvironment.langPack;
MTContext *context = [[MTContext alloc] initWithSerialization:currentContext.serialization encryptionProvider:currentContext.encryptionProvider apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:false];
context.makeTcpConnectionInterface = currentContext.makeTcpConnectionInterface;
NSInteger authTokenMasterDatacenterId = 0;
NSNumber *requiredAuthToken = nil;
bool allowUnboundEphemeralKeys = true;
NSString *keychainKey = [NSString stringWithFormat:@"%d:%@:%d", (int)address.datacenterId, address.ip, (int)address.port];
MTTemporaryKeychain *tempKeychain = [sharedFetchConfigKeychains() with:^(NSMutableDictionary *dict) {
if (dict[keychainKey] != nil) {
return (MTTemporaryKeychain *)dict[keychainKey];
} else {
MTTemporaryKeychain *keychain = [[MTTemporaryKeychain alloc] init];
dict[keychainKey] = keychain;
return keychain;
}
}];
context.keychain = tempKeychain;
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil requiredAuthToken:requiredAuthToken authTokenMasterDatacenterId:authTokenMasterDatacenterId];
mtProto.useTempAuthKeys = true;
mtProto.allowUnboundEphemeralKeys = allowUnboundEphemeralKeys;
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
[mtProto addMessageService:requestService];
[mtProto resume];
MTRequest *request = [[MTRequest alloc] init];
NSData *getConfigData = nil;
MTRequestDatacenterAddressListParser responseParser = [currentContext.serialization requestDatacenterAddressWithData:&getConfigData];
[request setPayload:getConfigData metadata:@"getConfig" shortMetadata:@"getConfig" responseParser:responseParser];
__weak MTContext *weakCurrentContext = currentContext;
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
[request setCompleted:^(MTDatacenterAddressListData *result, __unused MTRequestResponseInfo *info, id error)
{
if (error == nil) {
__strong MTContext *strongCurrentContext = weakCurrentContext;
if (strongCurrentContext != nil) {
[result.addressList enumerateKeysAndObjectsUsingBlock:^(NSNumber *nDatacenterId, NSArray *list, __unused BOOL *stop) {
MTDatacenterAddressSet *addressSet = [[MTDatacenterAddressSet alloc] initWithAddressList:list];
MTDatacenterAddressSet *currentAddressSet = [context addressSetForDatacenterWithId:[nDatacenterId integerValue]];
if (currentAddressSet == nil || ![addressSet isEqual:currentAddressSet])
{
if (MTLogEnabled()) {
MTLog(@"[Backup address fetch: updating datacenter %d address set to %@]", [nDatacenterId intValue], addressSet);
}
[strongCurrentContext updateAddressSetForDatacenterWithId:[nDatacenterId integerValue] addressSet:addressSet forceUpdateSchemes:true];
[subscriber putNext:@true];
[subscriber putCompletion];
}
}];
}
} else {
[subscriber putCompletion];
}
}];
[requestService addRequest:request];
id requestId = request.internalId;
return [[MTBlockDisposable alloc] initWithBlock:^{
[requestService removeRequestByInternalId:requestId];
[mtProto pause];
}];
}];
}
+ (MTSignal * _Nonnull)fetchBackupIps:(bool)isTestingEnvironment currentContext:(MTContext * _Nonnull)currentContext additionalSource:(MTSignal * _Nullable)additionalSource phoneNumber:(NSString * _Nullable)phoneNumber mainDatacenterId:(NSInteger)mainDatacenterId {
NSMutableArray *signals = [[NSMutableArray alloc] init];
[signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]];
[signals addObject:[self fetchBackupIpsResolveCloudflare:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext addressOverride:currentContext.apiEnvironment.accessHostOverride]];
if (additionalSource != nil) {
[signals addObject:[additionalSource mapToSignal:^MTSignal *(MTBackupDatacenterData *datacenterData) {
if (![datacenterData isKindOfClass:[MTBackupDatacenterData class]]) {
return [MTSignal complete];
}
if (datacenterData != nil && [self checkIpData:datacenterData timestamp:(int32_t)[currentContext globalTime] source:@"resolveExternal"]) {
return [MTSignal single:datacenterData];
} else {
return [MTSignal complete];
}
}]];
}
return [[[MTSignal mergeSignals:signals] take:1] mapToSignal:^MTSignal *(MTBackupDatacenterData *data) {
if (data != nil && data.addressList.count != 0) {
NSMutableArray *signals = [[NSMutableArray alloc] init];
NSTimeInterval delay = 0.0;
for (MTBackupDatacenterAddress *address in data.addressList) {
MTSignal *signal = [self fetchConfigFromAddress:address currentContext:currentContext mainDatacenterId:mainDatacenterId];
if (delay > DBL_EPSILON) {
signal = [signal delay:delay onQueue:[[MTQueue alloc] init]];
}
[signals addObject:signal];
delay += 5.0;
}
return [[MTSignal mergeSignals:signals] take:1];
}
return [MTSignal complete];
}];
}
@end
@@ -0,0 +1,19 @@
#import <Foundation/Foundation.h>
@interface MTBadMsgNotificationMessage : NSObject
@property (nonatomic, readonly) int64_t badMessageId;
@property (nonatomic, readonly) int32_t badMessageSeqNo;
@property (nonatomic, readonly) int32_t errorCode;
- (instancetype)initWithBadMessageId:(int64_t)badMessageId badMessageSeqNo:(int32_t)badMessageSeqNo errorCode:(int32_t)errorCode;
@end
@interface MTBadServerSaltNotificationMessage : MTBadMsgNotificationMessage
@property (nonatomic, readonly) int64_t nextServerSalt;
- (instancetype)initWithBadMessageId:(int64_t)badMessageId badMessageSeqNo:(int32_t)badMessageSeqNo errorCode:(int32_t)errorCode nextServerSalt:(int64_t)nextServerSalt;
@end
@@ -0,0 +1,31 @@
#import "MTBadMsgNotificationMessage.h"
@implementation MTBadMsgNotificationMessage
- (instancetype)initWithBadMessageId:(int64_t)badMessageId badMessageSeqNo:(int32_t)badMessageSeqNo errorCode:(int32_t)errorCode
{
self = [super init];
if (self != nil)
{
_badMessageId = badMessageId;
_badMessageSeqNo = badMessageSeqNo;
_errorCode = errorCode;
}
return self;
}
@end
@implementation MTBadServerSaltNotificationMessage
- (instancetype)initWithBadMessageId:(int64_t)badMessageId badMessageSeqNo:(int32_t)badMessageSeqNo errorCode:(int32_t)errorCode nextServerSalt:(int64_t)nextServerSalt
{
self = [super initWithBadMessageId:badMessageId badMessageSeqNo:badMessageSeqNo errorCode:errorCode];
if (self != nil)
{
_nextServerSalt = nextServerSalt;
}
return self;
}
@end
+74
View File
@@ -0,0 +1,74 @@
#import <MtProtoKit/MTBag.h>
@interface MTBag ()
{
NSInteger _nextKey;
NSMutableArray *_items;
NSMutableArray *_itemKeys;
}
@end
@implementation MTBag
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_items = [[NSMutableArray alloc] init];
_itemKeys = [[NSMutableArray alloc] init];
}
return self;
}
- (NSInteger)addItem:(id)item
{
if (item == nil)
return -1;
NSInteger key = _nextKey;
[_items addObject:item];
[_itemKeys addObject:@(key)];
_nextKey++;
return key;
}
- (void)enumerateItems:(void (^)(id))block
{
if (block)
{
for (id item in _items)
{
block(item);
}
}
}
- (void)removeItem:(NSInteger)key
{
NSUInteger index = 0;
for (NSNumber *itemKey in _itemKeys)
{
if ([itemKey integerValue] == key)
{
[_items removeObjectAtIndex:index];
[_itemKeys removeObjectAtIndex:index];
break;
}
index++;
}
}
- (bool)isEmpty
{
return _items.count == 0;
}
- (NSArray *)copyItems
{
return [[NSArray alloc] initWithArray:_items];
}
@end
@@ -0,0 +1,175 @@
#import <MtProtoKit/MTBindKeyMessageService.h>
#import <MtProtoKit/MTTime.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTOutgoingMessage.h>
#import <MtProtoKit/MTIncomingMessage.h>
#import <MtProtoKit/MTPreparedMessage.h>
#import <MtProtoKit/MTMessageTransaction.h>
#import <MtProtoKit/MTDatacenterSaltInfo.h>
#import <MtProtoKit/MTSessionInfo.h>
#import <MtProtoKit/MTRpcError.h>
#import <MtProtoKit/MTLogging.h>
#import "MTInternalMessageParser.h"
#import "MTRpcResultMessage.h"
#import "MTBuffer.h"
@interface MTBindKeyMessageService () {
MTDatacenterAuthKey *_persistentKey;
MTDatacenterAuthKey *_ephemeralKey;
void (^_completion)(bool);
int64_t _currentMessageId;
id _currentTransactionId;
}
@end
@implementation MTBindKeyMessageService
- (instancetype)initWithPersistentKey:(MTDatacenterAuthKey *)persistentKey ephemeralKey:(MTDatacenterAuthKey *)ephemeralKey completion:(void (^)(bool))completion {
self = [super init];
if (self != nil) {
_persistentKey = persistentKey;
_ephemeralKey = ephemeralKey;
_completion = [completion copy];
}
return self;
}
- (void)mtProtoDidAddService:(MTProto *)mtProto
{
[mtProto requestTransportTransaction];
}
- (MTMessageTransaction *)mtProtoMessageTransaction:(MTProto *)mtProto authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector sessionInfo:(MTSessionInfo *)sessionInfo scheme:(MTTransportScheme *)scheme
{
if (_currentTransactionId != nil) {
return nil;
}
int64_t bindingMessageId = [sessionInfo generateClientMessageId:NULL];
int32_t bindingSeqNo = [sessionInfo takeSeqNo:true];
int32_t expiresAt = (int32_t)([mtProto.context globalTime] + mtProto.context.tempKeyExpiration);
int64_t randomId = 0;
arc4random_buf(&randomId, 8);
int64_t nonce = 0;
arc4random_buf(&nonce, 8);
MTBuffer *decryptedMessage = [[MTBuffer alloc] init];
//bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner;
[decryptedMessage appendInt32:(int32_t)0x75a3f765];
[decryptedMessage appendInt64:nonce];
[decryptedMessage appendInt64:_ephemeralKey.authKeyId];
[decryptedMessage appendInt64:_persistentKey.authKeyId];
[decryptedMessage appendInt64:sessionInfo.sessionId];
[decryptedMessage appendInt32:expiresAt];
NSData *encryptedMessage = [MTProto _manuallyEncryptedMessage:[decryptedMessage data] messageId:bindingMessageId authKey:_persistentKey];
MTBuffer *bindRequestData = [[MTBuffer alloc] init];
//auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
[bindRequestData appendInt32:(int32_t)0xcdd42a05];
[bindRequestData appendInt64:_persistentKey.authKeyId];
[bindRequestData appendInt64:nonce];
[bindRequestData appendInt32:expiresAt];
[bindRequestData appendTLBytes:encryptedMessage];
if (MTLogEnabled()) {
MTLog(@"[MTBindKeyMessageService#%p binding temp %" PRId64 " to persistent %" PRId64 "]", self, _ephemeralKey.authKeyId, _persistentKey.authKeyId);
}
MTOutgoingMessage *outgoingMessage = [[MTOutgoingMessage alloc] initWithData:bindRequestData.data metadata:[NSString stringWithFormat:@"auth.bindTempAuthKey"] additionalDebugDescription:nil shortMetadata:@"auth.bindTempAuthKey" messageId:bindingMessageId messageSeqNo:bindingSeqNo];
return [[MTMessageTransaction alloc] initWithMessagePayload:@[outgoingMessage] prepared:nil failed:nil completion:^(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, __unused NSDictionary *messageInternalIdToQuickAckId) {
MTPreparedMessage *preparedMessage = messageInternalIdToPreparedMessage[outgoingMessage.internalId];
if (preparedMessage != nil && messageInternalIdToTransactionId[outgoingMessage.internalId] != nil) {
_currentMessageId = preparedMessage.messageId;
_currentTransactionId = messageInternalIdToTransactionId[outgoingMessage.internalId];
}
}];
return nil;
}
- (void)mtProto:(MTProto *)__unused mtProto messageDeliveryFailed:(int64_t)messageId {
if (messageId == _currentMessageId) {
_currentMessageId = 0;
_currentTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
- (void)mtProto:(MTProto *)mtProto transactionsMayHaveFailed:(NSArray *)transactionIds {
if (_currentTransactionId != nil && [transactionIds containsObject:_currentTransactionId]) {
_currentTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
- (void)mtProtoAllTransactionsMayHaveFailed:(MTProto *)mtProto {
if (_currentTransactionId != nil) {
_currentTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
- (void)mtProtoDidChangeSession:(MTProto *)mtProto {
_currentMessageId = 0;
_currentTransactionId = nil;
[mtProto requestTransportTransaction];
}
- (void)mtProtoServerDidChangeSession:(MTProto *)mtProto firstValidMessageId:(int64_t)firstValidMessageId messageIdsInFirstValidContainer:(NSArray *)messageIdsInFirstValidContainer {
if (_currentMessageId != 0 && _currentMessageId < firstValidMessageId && ![messageIdsInFirstValidContainer containsObject:@(_currentMessageId)]) {
_currentMessageId = 0;
_currentTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
- (void)mtProto:(MTProto *)mtProto receivedMessage:(MTIncomingMessage *)message authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector networkType:(int32_t)networkType {
if ([message.body isKindOfClass:[MTRpcResultMessage class]]) {
MTRpcResultMessage *rpcResultMessage = message.body;
if (rpcResultMessage.requestMessageId == _currentMessageId) {
bool success = false;
if (rpcResultMessage.data.length >= 4) {
uint32_t signature = 0;
[rpcResultMessage.data getBytes:&signature range:NSMakeRange(0, 4)];
id parsedMessage = [MTInternalMessageParser parseMessage:rpcResultMessage.data];
if ([parsedMessage isKindOfClass:[MTRpcError class]]) {
MTRpcError *rpcError = (MTRpcError *)parsedMessage;
if (MTLogEnabled()) {
MTLog(@"[MTRequestMessageService#%p response for %" PRId64 " is error: %d: %@]", self, _currentMessageId, (int)rpcError.errorCode, rpcError.errorDescription);
}
MTShortLog(@"[MTRequestMessageService#%p response for %" PRId64 " is error: %d: %@]", self, _currentMessageId, (int)rpcError.errorCode, rpcError.errorDescription);
}
//boolTrue#997275b5 = Bool;
if (signature == 0x997275b5U) {
success = true;
}
}
_completion(success);
}
}
}
-(void)complete {
_completion(true);
}
@end
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
@interface MTBindingTempAuthKeyContext : NSObject
@property (nonatomic, readonly) int64_t messageId;
@property (nonatomic, readonly) int32_t messageSeqNo;
@property (nonatomic, strong, readonly) id transactionId;
- (instancetype)initWithMessageId:(int64_t)messageId messageSeqNo:(int32_t)messageSeqNo transactionId:(id)transactionId;
@end
@@ -0,0 +1,17 @@
#import "MTBindingTempAuthKeyContext.h"
@implementation MTBindingTempAuthKeyContext
- (instancetype)initWithMessageId:(int64_t)messageId messageSeqNo:(int32_t)messageSeqNo transactionId:(id)transactionId
{
self = [super init];
if (self != nil)
{
_messageId = messageId;
_messageSeqNo = messageSeqNo;
_transactionId = transactionId;
}
return self;
}
@end
+18
View File
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
@interface MTBuffer : NSObject
- (void)appendInt32:(int32_t)value;
- (void)appendInt64:(int64_t)value;
- (void)appendBytes:(void const *)bytes length:(NSUInteger)length;
- (NSData *)data;
@end
@interface MTBuffer (TL)
- (void)appendTLBytes:(NSData *)bytes;
- (void)appendTLString:(NSString *)string;
@end
+90
View File
@@ -0,0 +1,90 @@
#import "MTBuffer.h"
@interface MTBuffer ()
{
NSMutableData *_data;
}
@end
@implementation MTBuffer
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_data = [[NSMutableData alloc] init];
}
return self;
}
- (void)appendInt32:(int32_t)value
{
[_data appendBytes:&value length:4];
}
- (void)appendInt64:(int64_t)value
{
[_data appendBytes:&value length:8];
}
- (void)appendBytes:(void const *)bytes length:(NSUInteger)length
{
[_data appendBytes:bytes length:length];
}
- (NSData *)data
{
return [[NSData alloc] initWithData:_data];
}
@end
static inline int roundUp(int numToRound, int multiple)
{
return multiple == 0 ? numToRound : ((numToRound % multiple) == 0 ? numToRound : (numToRound + multiple - (numToRound % multiple)));
}
@implementation MTBuffer (TL)
- (void)appendTLBytes:(NSData *)bytes
{
int32_t length = (int32_t)bytes.length;
if (bytes == nil || length == 0)
{
[self appendInt32:0];
return;
}
int paddingBytes = 0;
if (length >= 254)
{
uint8_t tmp = 254;
[self appendBytes:&tmp length:1];
[self appendBytes:(const uint8_t *)&length length:3];
paddingBytes = roundUp(length, 4) - length;
}
else
{
[self appendBytes:(const uint8_t *)&length length:1];
paddingBytes = roundUp(length + 1, 4) - (length + 1);
}
[self appendBytes:bytes.bytes length:length];
uint8_t tmp = 0;
for (int i = 0; i < paddingBytes; i++)
[self appendBytes:&tmp length:1];
}
- (void)appendTLString:(NSString *)string
{
[self appendTLBytes:[string dataUsingEncoding:NSUTF8StringEncoding]];
}
@end
@@ -0,0 +1,19 @@
#import "MTBuffer.h"
@interface MTBufferReader : NSObject
- (instancetype)initWithData:(NSData *)data;
- (bool)readBytes:(void *)bytes length:(NSUInteger)length;
- (bool)readInt32:(int32_t *)value;
- (bool)readInt64:(int64_t *)value;
- (NSData *)readRest;
@end
@interface MTBufferReader (TL)
- (bool)readTLString:(__autoreleasing NSString **)value;
- (bool)readTLBytes:(__autoreleasing NSData **)value;
@end
@@ -0,0 +1,126 @@
#import "MTBufferReader.h"
@interface MTBufferReader ()
{
NSData *_data;
NSUInteger _offset;
}
@end
@implementation MTBufferReader
- (instancetype)initWithData:(NSData *)data
{
self = [super init];
if (self != nil)
{
_data = data;
}
return self;
}
- (bool)readBytes:(void *)bytes length:(NSUInteger)length
{
if (_offset + length > _data.length)
return false;
if (bytes != NULL)
memcpy(bytes, _data.bytes + _offset, length);
_offset += length;
return true;
}
- (bool)readInt32:(int32_t *)value
{
return [self readBytes:value length:4];
}
- (bool)readInt64:(int64_t *)value
{
return [self readBytes:value length:8];
}
- (NSData *)readRest
{
return [_data subdataWithRange:NSMakeRange(_offset, _data.length - _offset)];
}
@end
static inline int roundUpInput(int32_t numToRound, int32_t multiple)
{
if (multiple == 0)
{
return numToRound;
}
int remainder = numToRound % multiple;
if (remainder == 0)
{
return numToRound;
}
return numToRound + multiple - remainder;
}
@implementation MTBufferReader (TL)
- (bool)readTLString:(__autoreleasing NSString **)value
{
NSData *bytes = nil;
if ([self readTLBytes:&bytes])
{
if (value)
*value = [[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding];
return true;
}
return false;
}
- (bool)readTLBytes:(__autoreleasing NSData **)value
{
uint8_t tmp = 0;
if ([self readBytes:&tmp length:1])
{
NSUInteger paddingBytes = 0;
int32_t length = tmp;
if (length == 254)
{
length = 0;
if (![self readBytes:((uint8_t *)&length) + 1 length:3])
return false;
length >>= 8;
paddingBytes = roundUpInput(length, 4) - length;
}
else
{
paddingBytes = roundUpInput(length + 1, 4) - (length + 1);
}
uint8_t *bytes = (uint8_t *)malloc(length);
if (![self readBytes:bytes length:length])
return false;
NSData *result = [NSData dataWithBytesNoCopy:bytes length:length freeWhenDone:true];
for (int i = 0; i < paddingBytes; i++)
{
if (![self readBytes:&tmp length:1])
return false;
}
if (value)
*value = result;
return true;
}
return false;
}
@end
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@class MTContext;
@class MTSocksProxySettings;
@interface MTConnectionProbing : NSObject
+ (MTSignal *)probeProxyWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId settings:(MTSocksProxySettings *)settings;
@end
@@ -0,0 +1,143 @@
#import "MTConnectionProbing.h"
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTQueue.h>
#import <MtProtoKit/MTAtomic.h>
#import <MtProtoKit/MTHttpRequestOperation.h>
#import <MtProtoKit/MTEncryption.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTRequest.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTDatacenterAddress.h>
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTProxyConnectivity.h>
#import "PingFoundation.h"
@interface MTPingHelper : NSObject <PingFoundationDelegate> {
void (^_success)();
PingFoundation *_ping;
}
@end
@implementation MTPingHelper
+ (void)runLoopThreadFunc {
while (true) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
}
}
+ (NSThread *)runLoopThread {
static NSThread *thread = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
thread = [[NSThread alloc] initWithTarget:self selector:@selector(runLoopThreadFunc) object:nil];
thread.name = @"MTPingHelper";
[thread start];
});
return thread;
}
+ (void)dispatchOnRunLoopThreadImpl:(void (^)())f {
if (f) {
f();
}
}
+ (void)dispatchOnRunLoopThread:(void (^)())block {
[self performSelector:@selector(dispatchOnRunLoopThreadImpl:) onThread:[self runLoopThread] withObject:[block copy] waitUntilDone:false];
}
- (instancetype)initWithSuccess:(void (^)())success {
self = [super init];
if (self != nil) {
_success = [success copy];
NSArray *hosts = @[
@"google.com",
@"8.8.8.8"
];
NSString *host = hosts[(int)(arc4random_uniform((uint32_t)hosts.count))];
_ping = [[PingFoundation alloc] initWithHostName:host];
_ping.delegate = self;
[_ping start];
}
return self;
}
- (void)dealloc {
#if DEBUG
assert(_ping.delegate == nil);
#endif
if (_ping.delegate != nil) {
_ping.delegate = nil;
[_ping stop];
}
}
- (void)stop {
_ping.delegate = nil;
[_ping stop];
}
- (void)pingFoundation:(PingFoundation *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber {
if (_success) {
_success();
}
}
- (void)pingFoundation:(PingFoundation *)pinger didStartWithAddress:(NSData *)__unused address {
[pinger sendPingWithData:nil];
}
@end
@implementation MTConnectionProbing
+ (MTSignal *)pingAddress {
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
MTMetaDisposable *disposable = [[MTMetaDisposable alloc] init];
[MTPingHelper dispatchOnRunLoopThread:^{
MTPingHelper *helper = [[MTPingHelper alloc] initWithSuccess:^{
[subscriber putNext:@true];
[subscriber putCompletion];
}];
[disposable setDisposable:[[MTBlockDisposable alloc] initWithBlock:^{
[MTPingHelper dispatchOnRunLoopThread:^{
[helper stop];
}];
}]];
}];
return disposable;
}];
}
+ (MTSignal *)probeProxyWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId settings:(MTSocksProxySettings *)settings {
MTSignal *proxyAvailable = [[[MTProxyConnectivity pingProxyWithContext:context datacenterId:datacenterId settings:settings] map:^id(MTProxyConnectivityStatus *status) {
return @(status.reachable);
}] timeout:10.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal single:@false]];
MTSignal *referenceAvailable = [[self pingAddress] timeout:10.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal single:@false]];
MTSignal *combined = [[MTSignal combineSignals:@[proxyAvailable, referenceAvailable]] map:^id(NSArray *values) {
NSNumber *proxy = values[0];
NSNumber *ping = values[1];
if (![proxy boolValue] && [ping boolValue]) {
return @true;
} else {
return @false;
}
}];
return combined;
}
@end
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
@class MTSignal;
@interface MTDNS : NSObject
+ (MTSignal *)resolveHostname:(NSString *)hostname;
+ (MTSignal *)resolveHostnameNative:(NSString *)hostname port:(int32_t)port;
+ (MTSignal *)resolveHostnameUniversal:(NSString *)hostname port:(int32_t)port;
@end
+340
View File
@@ -0,0 +1,340 @@
#import "MTDNS.h"
#import <arpa/inet.h>
#include <netinet/tcp.h>
#import <fcntl.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <netinet/in.h>
#import <net/if.h>
#import <MtProtoKit/MTQueue.h>
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTBag.h>
#import <MtProtoKit/MTAtomic.h>
#import <MtProtoKit/MTHttpRequestOperation.h>
#import <MtProtoKit/MTEncryption.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTRequest.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTDatacenterAddress.h>
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTLogging.h>
#import <netinet/in.h>
#import <arpa/inet.h>
@interface MTDNSHostContext : NSObject {
MTBag *_subscribers;
id<MTDisposable> _disposable;
}
@end
@implementation MTDNSHostContext
- (instancetype)initWithHost:(NSString *)host disposable:(id<MTDisposable>)disposable {
self = [super init];
if (self != nil) {
_subscribers = [[MTBag alloc] init];
_disposable = disposable;
}
return self;
}
- (void)dealloc {
[_disposable dispose];
}
- (NSInteger)addSubscriber:(void (^)(NSString *))completion {
return [_subscribers addItem:[completion copy]];
}
- (void)removeSubscriber:(NSInteger)index {
[_subscribers removeItem:index];
}
- (bool)isEmpty {
return [_subscribers isEmpty];
}
- (void)complete:(NSString *)result {
for (void (^completion)(NSString *) in [_subscribers copyItems]) {
completion(result);
}
}
@end
@interface MTDNSContext : NSObject {
NSMutableDictionary<NSString *, MTDNSHostContext *> *_contexts;
}
@end
@implementation MTDNSContext
+ (MTQueue *)sharedQueue {
static MTQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = [[MTQueue alloc] init];
});
return queue;
}
+ (MTSignal *)shared {
return [[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
static MTDNSContext *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[MTDNSContext alloc] init];
});
[subscriber putNext:instance];
[subscriber putCompletion];
return nil;
}] startOn:[self sharedQueue]];
}
- (instancetype)init {
self = [super init];
if (self != nil) {
_contexts = [[NSMutableDictionary alloc] init];
}
return self;
}
- (id<MTDisposable>)subscribe:(NSString *)host port:(int32_t)port completion:(void (^)(NSString *))completion {
NSString *key = [NSString stringWithFormat:@"%@:%d", host, port];
MTMetaDisposable *disposable = nil;
if (_contexts[key] == nil) {
disposable = [[MTMetaDisposable alloc] init];
_contexts[key] = [[MTDNSHostContext alloc] initWithHost:host disposable:disposable];
}
MTDNSHostContext *context = _contexts[key];
NSInteger index = [context addSubscriber:^(NSString *result) {
if (completion) {
completion(result);
}
}];
if (disposable != nil) {
__weak MTDNSContext *weakSelf = self;
[disposable setDisposable:[[[self performLookup:host port:port] deliverOn:[MTDNSContext sharedQueue]] startWithNextStrict:^(NSString *result) {
__strong MTDNSContext *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (strongSelf->_contexts[key] != nil) {
[strongSelf->_contexts[key] complete:result];
[strongSelf->_contexts removeObjectForKey:key];
}
} file:__FILE_NAME__ line:__LINE__]];
}
__weak MTDNSContext *weakSelf = self;
__weak MTDNSHostContext *weakContext = context;
return [[MTBlockDisposable alloc] initWithBlock:^{
[[MTDNSContext sharedQueue] dispatchOnQueue:^{
__strong MTDNSContext *strongSelf = weakSelf;
__strong MTDNSHostContext *strongContext = weakContext;
if (strongSelf == nil || strongContext == nil) {
return;
}
if (strongSelf->_contexts[key] != nil && strongSelf->_contexts[key] == strongContext) {
[strongSelf->_contexts[key] removeSubscriber:index];
if ([strongSelf->_contexts[key] isEmpty]) {
[strongSelf->_contexts removeObjectForKey:key];
}
}
}];
}];
}
- (MTSignal *)performLookup:(NSString *)host port:(int32_t)port {
MTSignal *lookupOnce = [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
MTMetaDisposable *disposable = [[MTMetaDisposable alloc] init];
[[MTQueue concurrentDefaultQueue] dispatchOnQueue:^{
struct addrinfo hints, *res, *res0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
NSString *portStr = [NSString stringWithFormat:@"%d", port];
if (MTLogEnabled()) {
MTLog(@"[MTDNS lookup %@:%@]", host, portStr);
}
int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
NSString *address4 = nil;
NSString *address6 = nil;
if (gai_error == 0) {
for(res = res0; res; res = res->ai_next) {
if ((address4 == nil) && (res->ai_family == AF_INET)) {
struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr;
char *s = malloc(INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
address4 = [NSString stringWithUTF8String:s];
free(s);
} else if ((address6 == nil) && (res->ai_family == AF_INET6)) {
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
char *s = malloc(INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
address6 = [NSString stringWithUTF8String:s];
free(s);
}
}
freeaddrinfo(res0);
}
if (address4 != nil) {
if (MTLogEnabled()) {
MTLog(@"[MTDNS lookup %@:%@ success ipv4]", host, portStr);
}
[subscriber putNext:address4];
[subscriber putCompletion];
} else if (address6 != nil) {
if (MTLogEnabled()) {
MTLog(@"[MTDNS lookup %@:%@ success ipv6]", host, portStr);
}
[subscriber putNext:address6];
[subscriber putCompletion];
} else {
if (MTLogEnabled()) {
MTLog(@"[MTDNS lookup %@:%@ error %d]", host, portStr, gai_error);
}
[subscriber putError:nil];
}
}];
return disposable;
}];
return [[[lookupOnce catch:^MTSignal *(__unused id error) {
return [[MTSignal complete] delay:2.0 onQueue:[MTDNSContext sharedQueue]];
}] restart] take:1];
}
@end
@interface MTDNSCachedHostname : NSObject
@property (nonatomic, strong) NSString *ip;
@property (nonatomic) NSTimeInterval timestamp;
@end
@implementation MTDNSCachedHostname
- (instancetype)initWithIp:(NSString *)ip timestamp:(NSTimeInterval)timestamp {
self = [super init];
if (self != nil) {
_ip = ip;
_timestamp = timestamp;
}
return self;
}
@end
@implementation MTDNS
+ (MTAtomic *)hostnameCache {
static MTAtomic *result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
result = [[MTAtomic alloc] initWithValue:[[NSMutableDictionary alloc] init]];
});
return result;
}
+ (NSString *)cachedIp:(NSString *)hostname {
return [[self hostnameCache] with:^id (NSMutableDictionary *dict) {
MTDNSCachedHostname *result = dict[hostname];
if (result != nil && result.timestamp > CFAbsoluteTimeGetCurrent() - 10.0 * 60.0) {
return result.ip;
}
return nil;
}];
}
+ (void)cacheIp:(NSString *)hostname ip:(NSString *)ip {
[[self hostnameCache] with:^id (NSMutableDictionary *dict) {
dict[hostname] = [[MTDNSCachedHostname alloc] initWithIp:ip timestamp:CFAbsoluteTimeGetCurrent()];
return nil;
}];
}
+ (MTSignal *)resolveHostname:(NSString *)hostname {
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
NSString *cached = [self cachedIp:hostname];
if (cached != nil) {
[subscriber putNext:cached];
[subscriber putCompletion];
return nil;
}
NSDictionary *headers = @{@"Host": @"dns.google.com"};
return [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://google.com/resolve?name=%@", hostname]] headers:headers] mapToSignal:^MTSignal *(MTHttpResponse *response) {
NSData *data = response.data;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([dict respondsToSelector:@selector(objectForKey:)]) {
NSArray *answer = dict[@"Answer"];
if ([answer respondsToSelector:@selector(objectAtIndex:)]) {
for (NSDictionary *item in answer) {
if ([item respondsToSelector:@selector(objectForKey:)]) {
NSString *itemData = item[@"data"];
if ([itemData respondsToSelector:@selector(characterAtIndex:)]) {
bool isIp = true;
struct in_addr ip4;
struct in6_addr ip6;
if (inet_aton(itemData.UTF8String, &ip4) == 0) {
if (inet_pton(AF_INET6, itemData.UTF8String, &ip6) == 0) {
isIp = false;
}
}
if (isIp) {
[self cacheIp:hostname ip:itemData];
return [MTSignal single:itemData];
}
}
}
}
}
}
[subscriber putNext:hostname];
[subscriber putCompletion];
return nil;
}] startWithNext:^(id next) {
[subscriber putNext:next];
[subscriber putCompletion];
} error:^(id error) {
[subscriber putNext:hostname];
[subscriber putCompletion];
} completed:nil];
}];
}
+ (MTSignal *)resolveHostnameNative:(NSString *)hostname port:(int32_t)port {
return [[MTDNSContext shared] mapToSignal:^MTSignal *(MTDNSContext *context) {
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
return [context subscribe:hostname port:port completion:^(NSString *result) {
[subscriber putNext:result];
[subscriber putCompletion];
}];
}];
}];
}
+ (MTSignal *)resolveHostnameUniversal:(NSString *)hostname port:(int32_t)port {
return [[self resolveHostname:hostname] timeout:10.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[self resolveHostnameNative:hostname port:port]];
}
@end
@@ -0,0 +1,122 @@
#import <MtProtoKit/MTDatacenterAddress.h>
#import <netinet/in.h>
#import <arpa/inet.h>
@implementation MTDatacenterAddress
- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy secret:(NSData *)secret
{
self = [super init];
if (self != nil)
{
_ip = ip;
_port = port;
_preferForMedia = preferForMedia;
_restrictToTcp = restrictToTcp;
_cdn = cdn;
_preferForProxy = preferForProxy;
_secret = secret;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self != nil)
{
_ip = [aDecoder decodeObjectForKey:@"ip"];
_host = [aDecoder decodeObjectForKey:@"host"];
_port = (uint16_t)[aDecoder decodeIntForKey:@"port"];
_preferForMedia = [aDecoder decodeBoolForKey:@"preferForMedia"];
_restrictToTcp = [aDecoder decodeBoolForKey:@"restrictToTcp"];
_cdn = [aDecoder decodeBoolForKey:@"cdn"];
_preferForProxy = [aDecoder decodeBoolForKey:@"preferForProxy"];
_secret = [aDecoder decodeObjectForKey:@"secret"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_ip forKey:@"ip"];
[aCoder encodeObject:_host forKey:@"host"];
[aCoder encodeInt:_port forKey:@"port"];
[aCoder encodeBool:_preferForMedia forKey:@"preferForMedia"];
[aCoder encodeBool:_restrictToTcp forKey:@"restrictToTcp"];
[aCoder encodeBool:_cdn forKey:@"cdn"];
[aCoder encodeBool:_preferForProxy forKey:@"preferForProxy"];
[aCoder encodeObject:_secret forKey:@"secret"];
}
- (instancetype)copyWithZone:(NSZone *)__unused zone {
return self;
}
- (BOOL)isEqual:(id)object
{
if (![object isKindOfClass:[MTDatacenterAddress class]])
return false;
return [self isEqualToAddress:object];
}
- (NSUInteger)hash {
return [_ip hash] * 31 + ((NSUInteger)_port);
}
- (BOOL)isEqualToAddress:(MTDatacenterAddress *)other
{
if (![other isKindOfClass:[MTDatacenterAddress class]])
return false;
if (![_ip isEqualToString:other.ip])
return false;
if (_port != other.port)
return false;
if (_preferForMedia != other.preferForMedia)
return false;
if (_restrictToTcp != other.restrictToTcp) {
return false;
}
if (_cdn != other.cdn) {
return false;
}
if (_preferForProxy != other.preferForProxy) {
return false;
}
if ((_secret != nil) && (other->_secret != nil)) {
if (![_secret isEqualToData:other->_secret]) {
return false;
}
} else if ((_secret != nil) != (other->_secret != nil)) {
return false;
}
return true;
}
- (BOOL)isIpv6
{
const char *utf8 = [_ip UTF8String];
int success;
struct in6_addr dst6;
success = inet_pton(AF_INET6, utf8, &dst6);
return success == 1;
}
- (NSString *)description
{
return [[NSString alloc] initWithFormat:@"%@:%d (media: %@, cdn: %@, static: %@, secret: %@)", _ip == nil ? _host : _ip, (int)_port, _preferForMedia ? @"yes" : @"no", _cdn ? @"yes" : @"no", _preferForProxy ? @"yes" : @"no", _secret];
}
@end
@@ -0,0 +1,19 @@
#import <MtProtoKit/MTDatacenterAddressListData.h>
@implementation MTDatacenterAddressListData
- (instancetype)initWithAddressList:(NSDictionary<NSNumber *, NSArray *> *)addressList
{
self = [super init];
if (self != nil)
{
_addressList = addressList;
}
return self;
}
- (NSString *)description {
return _addressList.description;
}
@end
@@ -0,0 +1,69 @@
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTDatacenterAddress.h>
@implementation MTDatacenterAddressSet
- (instancetype)initWithAddressList:(NSArray *)addressList
{
self = [super init];
if (self != nil)
{
_addressList = addressList;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self != nil)
{
_addressList = [aDecoder decodeObjectForKey:@"addressList"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_addressList forKey:@"addressList"];
}
- (BOOL)isEqual:(MTDatacenterAddressSet *)another
{
if (![another isKindOfClass:[MTDatacenterAddressSet class]])
return false;
if (_addressList.count != another.addressList.count)
return false;
for (NSUInteger i = 0; i < _addressList.count; i++)
{
if (![_addressList[i] isEqual:another.addressList[i]])
return false;
}
return true;
}
- (NSString *)description
{
NSMutableString *string = [[NSMutableString alloc] init];
[string appendString:@"["];
for (MTDatacenterAddress *address in _addressList)
{
if (string.length != 1)
[string appendString:@", "];
[string appendString:[address description]];
}
[string appendString:@"]"];
return string;
}
- (MTDatacenterAddress *)firstAddress
{
return _addressList.count == 0 ? nil : _addressList[0];
}
@end
@@ -0,0 +1,211 @@
#import <MtProtoKit/MTDatacenterAuthAction.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTRequest.h>
#import <MtProtoKit/MTDatacenterSaltInfo.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTDatacenterAddressSet.h>
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTDatacenterAuthMessageService.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTBindKeyMessageService.h>
#import "MTBuffer.h"
@interface MTDatacenterAuthAction () <MTDatacenterAuthMessageServiceDelegate>
{
void (^_completion)(MTDatacenterAuthAction *, bool);
bool _isCdn;
bool _skipBind;
MTDatacenterAuthInfoSelector _authKeyInfoSelector;
NSInteger _datacenterId;
__weak MTContext *_context;
bool _awaitingAddresSetUpdate;
MTProto *_authMtProto;
MTProto *_bindMtProto;
}
@end
@implementation MTDatacenterAuthAction
- (instancetype)initWithAuthKeyInfoSelector:(MTDatacenterAuthInfoSelector)authKeyInfoSelector isCdn:(bool)isCdn skipBind:(bool)skipBind completion:(void (^)(MTDatacenterAuthAction *, bool))completion {
self = [super init];
if (self != nil) {
_authKeyInfoSelector = authKeyInfoSelector;
_isCdn = isCdn;
_skipBind = skipBind;
_completion = [completion copy];
}
return self;
}
- (void)dealloc {
[self cleanup];
}
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId {
_datacenterId = datacenterId;
_context = context;
if (_datacenterId != 0 && context != nil)
{
bool alreadyCompleted = false;
MTDatacenterAuthInfo *currentAuthInfo = [context authInfoForDatacenterWithId:_datacenterId selector:_authKeyInfoSelector];
if (currentAuthInfo != nil) {
alreadyCompleted = true;
}
if (alreadyCompleted) {
[self complete];
} else {
_authMtProto = [[MTProto alloc] initWithContext:context datacenterId:_datacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
_authMtProto.cdn = _isCdn;
_authMtProto.useUnauthorizedMode = true;
bool tempAuth = false;
switch (_authKeyInfoSelector) {
case MTDatacenterAuthInfoSelectorEphemeralMain:
tempAuth = true;
_authMtProto.media = false;
break;
case MTDatacenterAuthInfoSelectorEphemeralMedia:
tempAuth = true;
_authMtProto.media = true;
_authMtProto.enforceMedia = true;
break;
default:
break;
}
MTDatacenterAuthMessageService *authService = [[MTDatacenterAuthMessageService alloc] initWithContext:context tempAuth:tempAuth];
authService.delegate = self;
[_authMtProto addMessageService:authService];
[_authMtProto resume];
}
}
else
[self fail];
}
- (void)authMessageServiceCompletedWithAuthKey:(MTDatacenterAuthKey *)authKey timestamp:(int64_t)timestamp {
[self completeWithAuthKey:authKey timestamp:timestamp];
}
- (void)completeWithAuthKey:(MTDatacenterAuthKey *)authKey timestamp:(int64_t)timestamp {
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthAction#%p@%p: completeWithAuthKey %lld selector %d]", self, _context, authKey.authKeyId, _authKeyInfoSelector);
}
switch (_authKeyInfoSelector) {
case MTDatacenterAuthInfoSelectorPersistent: {
MTDatacenterAuthInfo *authInfo = [[MTDatacenterAuthInfo alloc] initWithAuthKey:authKey.authKey authKeyId:authKey.authKeyId validUntilTimestamp:INT32_MAX saltSet:@[[[MTDatacenterSaltInfo alloc] initWithSalt:0 firstValidMessageId:timestamp lastValidMessageId:timestamp + (29.0 * 60.0) * 4294967296]] authKeyAttributes:nil];
MTContext *context = _context;
[context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo selector:_authKeyInfoSelector];
[self complete];
}
break;
case MTDatacenterAuthInfoSelectorEphemeralMain:
case MTDatacenterAuthInfoSelectorEphemeralMedia: {
MTContext *mainContext = _context;
if (mainContext != nil) {
if (_skipBind) {
MTDatacenterAuthInfo *authInfo = [[MTDatacenterAuthInfo alloc] initWithAuthKey:authKey.authKey authKeyId:authKey.authKeyId validUntilTimestamp:authKey.validUntilTimestamp saltSet:@[[[MTDatacenterSaltInfo alloc] initWithSalt:0 firstValidMessageId:timestamp lastValidMessageId:timestamp + (29.0 * 60.0) * 4294967296]] authKeyAttributes:nil];
[_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo selector:_authKeyInfoSelector];
[self complete];
} else {
MTDatacenterAuthInfo *persistentAuthInfo = [mainContext authInfoForDatacenterWithId:_datacenterId selector:MTDatacenterAuthInfoSelectorPersistent];
if (persistentAuthInfo != nil) {
_bindMtProto = [[MTProto alloc] initWithContext:mainContext datacenterId:_datacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
_bindMtProto.cdn = false;
_bindMtProto.useUnauthorizedMode = false;
_bindMtProto.useTempAuthKeys = true;
_bindMtProto.useExplicitAuthKey = authKey;
_bindMtProto.tempConnectionForReuse = [_authMtProto takeConnectionForReusing];
switch (_authKeyInfoSelector) {
case MTDatacenterAuthInfoSelectorEphemeralMain:
_bindMtProto.media = false;
break;
case MTDatacenterAuthInfoSelectorEphemeralMedia:
_bindMtProto.media = true;
_bindMtProto.enforceMedia = true;
break;
default:
break;
}
__weak MTDatacenterAuthAction *weakSelf = self;
[_bindMtProto addMessageService:[[MTBindKeyMessageService alloc] initWithPersistentKey:[[MTDatacenterAuthKey alloc] initWithAuthKey:persistentAuthInfo.authKey authKeyId:persistentAuthInfo.authKeyId validUntilTimestamp:persistentAuthInfo.validUntilTimestamp notBound:false] ephemeralKey:authKey completion:^(bool success) {
__strong MTDatacenterAuthAction *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf->_bindMtProto stop];
if (success) {
MTDatacenterAuthInfo *authInfo = [[MTDatacenterAuthInfo alloc] initWithAuthKey:authKey.authKey authKeyId:authKey.authKeyId validUntilTimestamp:authKey.validUntilTimestamp saltSet:@[[[MTDatacenterSaltInfo alloc] initWithSalt:0 firstValidMessageId:timestamp lastValidMessageId:timestamp + (29.0 * 60.0) * 4294967296]] authKeyAttributes:nil];
[strongSelf->_context updateAuthInfoForDatacenterWithId:strongSelf->_datacenterId authInfo:authInfo selector:strongSelf->_authKeyInfoSelector];
[strongSelf complete];
} else {
[strongSelf fail];
}
}]];
[_bindMtProto resume];
}
}
}
}
break;
default:
assert(false);
break;
}
}
- (void)cleanup
{
MTProto *authMtProto = _authMtProto;
_authMtProto = nil;
[authMtProto stop];
MTProto *bindMtProto = _bindMtProto;
_bindMtProto = nil;
[bindMtProto stop];
}
- (void)cancel
{
[self cleanup];
}
- (void)complete {
if (_completion) {
_completion(self, true);
}
}
- (void)fail
{
if (_completion) {
_completion(self, false);
}
}
@end
@@ -0,0 +1,138 @@
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTDatacenterSaltInfo.h>
@implementation MTDatacenterAuthKey
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId validUntilTimestamp:(int32_t)validUntilTimestamp notBound:(bool)notBound {
self = [super init];
if (self != nil) {
_authKey = authKey;
_authKeyId = authKeyId;
_validUntilTimestamp = validUntilTimestamp;
_notBound = notBound;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
int32_t validUntilTimestamp = [aDecoder decodeInt32ForKey:@"validUntilTimestamp"];
if (validUntilTimestamp == 0) {
validUntilTimestamp = INT32_MAX;
}
return [self initWithAuthKey:[aDecoder decodeObjectForKey:@"key"] authKeyId:[aDecoder decodeInt64ForKey:@"keyId"] validUntilTimestamp:validUntilTimestamp notBound:[aDecoder decodeBoolForKey:@"notBound"]];
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:_authKey forKey:@"key"];
[aCoder encodeInt64:_authKeyId forKey:@"keyId"];
[aCoder encodeInt32:_validUntilTimestamp forKey:@"validUntilTimestamp"];
[aCoder encodeBool:_notBound forKey:@"notBound"];
}
@end
@implementation MTDatacenterAuthInfo
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId validUntilTimestamp:(int32_t)validUntilTimestamp saltSet:(NSArray *)saltSet authKeyAttributes:(NSDictionary *)authKeyAttributes
{
self = [super init];
if (self != nil)
{
_authKey = authKey;
_authKeyId = authKeyId;
_saltSet = saltSet;
_validUntilTimestamp = validUntilTimestamp;
_authKeyAttributes = authKeyAttributes;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self != nil)
{
_authKey = [aDecoder decodeObjectForKey:@"authKey"];
_authKeyId = [aDecoder decodeInt64ForKey:@"authKeyId"];
int32_t validUntilTimestamp = [aDecoder decodeInt32ForKey:@"validUntilTimestamp"];
_validUntilTimestamp = validUntilTimestamp;
_saltSet = [aDecoder decodeObjectForKey:@"saltSet"];
_authKeyAttributes = [aDecoder decodeObjectForKey:@"authKeyAttributes"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_authKey forKey:@"authKey"];
[aCoder encodeInt64:_authKeyId forKey:@"authKeyId"];
[aCoder encodeInt32:_validUntilTimestamp forKey:@"validUntilTimestamp"];
[aCoder encodeObject:_saltSet forKey:@"saltSet"];
[aCoder encodeObject:_authKeyAttributes forKey:@"authKeyAttributes"];
}
- (int64_t)authSaltForMessageId:(int64_t)messageId
{
int64_t bestSalt = 0;
int64_t bestValidMessageCount = 0;
for (MTDatacenterSaltInfo *saltInfo in _saltSet)
{
int64_t currentValidMessageCount = [saltInfo validMessageCountAfterId:messageId];
if (currentValidMessageCount != 0 && currentValidMessageCount > bestValidMessageCount)
bestSalt = saltInfo.salt;
}
return bestSalt;
}
- (MTDatacenterAuthInfo *)mergeSaltSet:(NSArray *)updatedSaltSet forTimestamp:(NSTimeInterval)timestamp
{
int64_t referenceMessageId = (int64_t)(timestamp * 4294967296);
NSMutableArray *mergedSaltSet = [[NSMutableArray alloc] init];
for (MTDatacenterSaltInfo *saltInfo in _saltSet)
{
if ([saltInfo isValidFutureSaltForMessageId:referenceMessageId])
[mergedSaltSet addObject:saltInfo];
}
for (MTDatacenterSaltInfo *saltInfo in updatedSaltSet)
{
bool alreadExists = false;
for (MTDatacenterSaltInfo *existingSaltInfo in mergedSaltSet)
{
if (existingSaltInfo.firstValidMessageId == saltInfo.firstValidMessageId)
{
alreadExists = true;
break;
}
}
if (!alreadExists)
{
if ([saltInfo isValidFutureSaltForMessageId:referenceMessageId])
[mergedSaltSet addObject:saltInfo];
}
}
return [[MTDatacenterAuthInfo alloc] initWithAuthKey:_authKey authKeyId:_authKeyId validUntilTimestamp:_validUntilTimestamp saltSet:mergedSaltSet authKeyAttributes:_authKeyAttributes];
}
- (MTDatacenterAuthInfo *)withUpdatedAuthKeyAttributes:(NSDictionary *)authKeyAttributes {
return [[MTDatacenterAuthInfo alloc] initWithAuthKey:_authKey authKeyId:_authKeyId validUntilTimestamp:_validUntilTimestamp saltSet:_saltSet authKeyAttributes:authKeyAttributes];
}
- (MTDatacenterAuthKey *)persistentAuthKey {
return [[MTDatacenterAuthKey alloc] initWithAuthKey:_authKey authKeyId:_authKeyId validUntilTimestamp:_validUntilTimestamp notBound:false];
}
- (NSString *)description {
return [NSString stringWithFormat:@"MTDatacenterAuthInfo authKeyId:%" PRId64 " authKey:%lu", _authKeyId, (unsigned long)_authKey.length];
}
@end
@@ -0,0 +1,866 @@
#import <MtProtoKit/MTDatacenterAuthMessageService.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTSessionInfo.h>
#import <MtProtoKit/MTIncomingMessage.h>
#import <MtProtoKit/MTOutgoingMessage.h>
#import <MtProtoKit/MTMessageTransaction.h>
#import <MtProtoKit/MTPreparedMessage.h>
#import <MtProtoKit/MTDatacenterAuthInfo.h>
#import <MtProtoKit/MTDatacenterSaltInfo.h>
#import "MTBuffer.h"
#import <MtProtoKit/MTEncryption.h>
#import <CommonCrypto/CommonCrypto.h>
#import "MTInternalMessageParser.h"
#import "MTServerDhInnerDataMessage.h"
#import "MTResPqMessage.h"
#import "MTServerDhParamsMessage.h"
#import "MTSetClientDhParamsResponseMessage.h"
@interface MTDatacenterAuthPublicKey : NSObject
@property (nonatomic, strong, readonly) NSString *publicKey;
@end
@implementation MTDatacenterAuthPublicKey
- (instancetype)initWithPublicKey:(NSString *)publicKey {
self = [super init];
if (self != nil) {
_publicKey = publicKey;
}
return self;
}
- (uint64_t)fingerprintWithEncryptionProvider:(id<EncryptionProvider>)encryptionProvider {
return MTRsaFingerprint(encryptionProvider, _publicKey);
}
@end
static NSArray<MTDatacenterAuthPublicKey *> *defaultPublicKeys(bool isProduction) {
static NSArray<MTDatacenterAuthPublicKey *> *testingPublicKeys = nil;
static NSArray<MTDatacenterAuthPublicKey *> *productionPublicKeys = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
testingPublicKeys = @[
[[MTDatacenterAuthPublicKey alloc] initWithPublicKey:@"-----BEGIN RSA PUBLIC KEY-----\n"
"MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n"
"yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n"
"plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n"
"j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n"
"aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n"
"j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n"
"-----END RSA PUBLIC KEY-----"]
];
productionPublicKeys = @[
[[MTDatacenterAuthPublicKey alloc] initWithPublicKey:@"-----BEGIN RSA PUBLIC KEY-----\n"
"MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n"
"5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n"
"62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n"
"+aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n"
"t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n"
"5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n"
"-----END RSA PUBLIC KEY-----"]
];
});
if (isProduction) {
return productionPublicKeys;
} else {
return testingPublicKeys;
}
}
static MTDatacenterAuthPublicKey *selectPublicKey(id<EncryptionProvider> encryptionProvider, NSArray<NSNumber *> *fingerprints, NSArray<MTDatacenterAuthPublicKey *> *publicKeys) {
for (NSNumber *nFingerprint in fingerprints) {
for (MTDatacenterAuthPublicKey *key in publicKeys) {
uint64_t keyFingerprint = [key fingerprintWithEncryptionProvider:encryptionProvider];
if ([nFingerprint unsignedLongLongValue] == keyFingerprint) {
return key;
}
}
}
return nil;
}
typedef enum {
MTDatacenterAuthStageWaitingForPublicKeys = 0,
MTDatacenterAuthStagePQ = 1,
MTDatacenterAuthStageReqDH = 2,
MTDatacenterAuthStageKeyVerification = 3,
MTDatacenterAuthStageDone = 4
} MTDatacenterAuthStage;
@interface MTDatacenterAuthMessageService ()
{
id<EncryptionProvider> _encryptionProvider;
bool _tempAuth;
MTDatacenterAuthStage _stage;
int64_t _currentStageMessageId;
int32_t _currentStageMessageSeqNo;
id _currentStageTransactionId;
NSData *_nonce;
NSData *_serverNonce;
NSData *_newNonce;
NSData *_dhP;
NSData *_dhQ;
int64_t _dhPublicKeyFingerprint;
NSData *_dhEncryptedData;
MTDatacenterAuthKey *_authKey;
NSData *_encryptedClientData;
NSArray<MTDatacenterAuthPublicKey *> *_publicKeys;
}
@end
@implementation MTDatacenterAuthMessageService
- (instancetype)initWithContext:(MTContext *)context tempAuth:(bool)tempAuth
{
self = [super init];
if (self != nil)
{
_encryptionProvider = context.encryptionProvider;
_tempAuth = tempAuth;
}
return self;
}
- (NSArray<MTDatacenterAuthPublicKey *> *)convertPublicKeysFromDictionaries:(NSArray<NSDictionary *> *)list {
NSMutableArray<MTDatacenterAuthPublicKey *> *cdnKeys = [[NSMutableArray alloc] init];
for (NSDictionary *dict in list) {
NSString *key = dict[@"key"];
if ([key isKindOfClass:[NSString class]]) {
[cdnKeys addObject:[[MTDatacenterAuthPublicKey alloc] initWithPublicKey:key]];
}
}
return cdnKeys;
}
- (void)reset:(MTProto *)mtProto
{
_currentStageMessageId = 0;
_currentStageMessageSeqNo = 0;
_currentStageTransactionId = nil;
_nonce = nil;
_serverNonce = nil;
_newNonce = nil;
_dhP = nil;
_dhQ = nil;
_dhPublicKeyFingerprint = 0;
_dhEncryptedData = nil;
_authKey = nil;
_encryptedClientData = nil;
if (mtProto.cdn) {
_publicKeys = [self convertPublicKeysFromDictionaries:[mtProto.context publicKeysForDatacenterWithId:mtProto.datacenterId]];
if (_publicKeys.count == 0) {
_stage = MTDatacenterAuthStageWaitingForPublicKeys;
[mtProto.context publicKeysForDatacenterWithIdRequired:mtProto.datacenterId];
} else {
_stage = MTDatacenterAuthStagePQ;
}
} else {
_publicKeys = defaultPublicKeys(!mtProto.context.isTestingEnvironment);
_stage = MTDatacenterAuthStagePQ;
}
[mtProto requestSecureTransportReset];
[mtProto requestTransportTransaction];
}
- (void)mtProtoDidAddService:(MTProto *)mtProto
{
[self reset:mtProto];
}
- (void)mtProtoPublicKeysUpdated:(MTProto *)mtProto datacenterId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> *)publicKeys {
if (!mtProto.cdn) {
return;
}
if (_stage == MTDatacenterAuthStageWaitingForPublicKeys) {
if (mtProto.datacenterId == datacenterId) {
_publicKeys = [self convertPublicKeysFromDictionaries:publicKeys];
if (_publicKeys != nil && _publicKeys.count != 0) {
_stage = MTDatacenterAuthStagePQ;
[mtProto requestTransportTransaction];
}
}
}
}
- (MTMessageTransaction *)mtProtoMessageTransaction:(MTProto *)mtProto authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector sessionInfo:(MTSessionInfo *)sessionInfo scheme:(MTTransportScheme *)scheme
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p mtProto#%p (media: %s) mtProtoMessageTransaction scheme:%@]", self, mtProto, mtProto.media ? "true" : "false", scheme);
}
if (_currentStageTransactionId == nil)
{
switch (_stage)
{
case MTDatacenterAuthStageWaitingForPublicKeys:
break;
case MTDatacenterAuthStagePQ:
{
if (_nonce == nil)
{
uint8_t nonceBytes[16];
__unused int result = SecRandomCopyBytes(kSecRandomDefault, 16, nonceBytes);
_nonce = [[NSData alloc] initWithBytes:nonceBytes length:16];
}
MTBuffer *reqPqBuffer = [[MTBuffer alloc] init];
[reqPqBuffer appendInt32:(int32_t)0xbe7e8ef1];
[reqPqBuffer appendBytes:_nonce.bytes length:_nonce.length];
NSString *messageDescription = [NSString stringWithFormat:@"reqPq nonce:%@", _nonce];
MTOutgoingMessage *message = [[MTOutgoingMessage alloc] initWithData:reqPqBuffer.data metadata:messageDescription additionalDebugDescription:nil shortMetadata:messageDescription messageId:_currentStageMessageId messageSeqNo:_currentStageMessageSeqNo];
return [[MTMessageTransaction alloc] initWithMessagePayload:@[message] prepared:nil failed:nil completion:^(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, __unused NSDictionary *messageInternalIdToQuickAckId)
{
if (_stage == MTDatacenterAuthStagePQ && messageInternalIdToTransactionId[message.internalId] != nil && messageInternalIdToPreparedMessage[message.internalId] != nil)
{
MTPreparedMessage *preparedMessage = messageInternalIdToPreparedMessage[message.internalId];
_currentStageMessageId = preparedMessage.messageId;
_currentStageMessageSeqNo = preparedMessage.seqNo;
_currentStageTransactionId = messageInternalIdToTransactionId[message.internalId];
}
}];
}
case MTDatacenterAuthStageReqDH:
{
#if DEBUG
if (arc4random_uniform(100) < 50) {
[mtProto simulateDisconnection];
}
#endif
MTBuffer *reqDhBuffer = [[MTBuffer alloc] init];
[reqDhBuffer appendInt32:(int32_t)0xd712e4be];
[reqDhBuffer appendBytes:_nonce.bytes length:_nonce.length];
[reqDhBuffer appendBytes:_serverNonce.bytes length:_serverNonce.length];
[reqDhBuffer appendTLBytes:_dhP];
[reqDhBuffer appendTLBytes:_dhQ];
[reqDhBuffer appendInt64:_dhPublicKeyFingerprint];
[reqDhBuffer appendTLBytes:_dhEncryptedData];
NSString *messageDescription = [NSString stringWithFormat:@"reqDh nonce:%@ serverNonce:%@ p:%@ q:%@ fingerprint:%llx dhEncryptedData:%d bytes", _nonce, _serverNonce, _dhP, _dhQ, _dhPublicKeyFingerprint, (int)_dhEncryptedData.length];
MTOutgoingMessage *message = [[MTOutgoingMessage alloc] initWithData:reqDhBuffer.data metadata:messageDescription additionalDebugDescription:nil shortMetadata:messageDescription messageId:_currentStageMessageId messageSeqNo:_currentStageMessageSeqNo];
return [[MTMessageTransaction alloc] initWithMessagePayload:@[message] prepared:nil failed:nil completion:^(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, __unused NSDictionary *messageInternalIdToQuickAckId)
{
if (_stage == MTDatacenterAuthStageReqDH && messageInternalIdToTransactionId[message.internalId] != nil && messageInternalIdToPreparedMessage[message.internalId] != nil)
{
MTPreparedMessage *preparedMessage = messageInternalIdToPreparedMessage[message.internalId];
_currentStageMessageId = preparedMessage.messageId;
_currentStageMessageSeqNo = preparedMessage.seqNo;
_currentStageTransactionId = messageInternalIdToTransactionId[message.internalId];
}
}];
}
case MTDatacenterAuthStageKeyVerification:
{
MTBuffer *setDhParamsBuffer = [[MTBuffer alloc] init];
[setDhParamsBuffer appendInt32:(int32_t)0xf5045f1f];
[setDhParamsBuffer appendBytes:_nonce.bytes length:_nonce.length];
[setDhParamsBuffer appendBytes:_serverNonce.bytes length:_serverNonce.length];
[setDhParamsBuffer appendTLBytes:_encryptedClientData];
MTOutgoingMessage *message = [[MTOutgoingMessage alloc] initWithData:setDhParamsBuffer.data metadata:@"setDhParams" additionalDebugDescription:nil shortMetadata:@"setDhParams" messageId:_currentStageMessageId messageSeqNo:_currentStageMessageSeqNo];
return [[MTMessageTransaction alloc] initWithMessagePayload:@[message] prepared:nil failed:nil completion:^(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, __unused NSDictionary *messageInternalIdToQuickAckId)
{
if (_stage == MTDatacenterAuthStageKeyVerification && messageInternalIdToTransactionId[message.internalId] != nil && messageInternalIdToPreparedMessage[message.internalId] != nil)
{
MTPreparedMessage *preparedMessage = messageInternalIdToPreparedMessage[message.internalId];
_currentStageMessageId = preparedMessage.messageId;
_currentStageMessageSeqNo = preparedMessage.seqNo;
_currentStageTransactionId = messageInternalIdToTransactionId[message.internalId];
}
}];
}
default:
break;
}
}
return nil;
}
static NSData *reversedBytes(NSData *data) {
NSMutableData *result = [[NSMutableData alloc] initWithLength:data.length];
for (NSUInteger i = 0; i < result.length; i++) {
((uint8_t *)result.mutableBytes)[i] = ((uint8_t *)data.bytes)[result.length - i - 1];
}
return result;
}
static NSData *encryptRSAModernPadding(id<EncryptionProvider> encryptionProvider, NSData *pqInnerData, NSString *publicKey) {
NSMutableData *dataWithPadding = [[NSMutableData alloc] init];
[dataWithPadding appendData:pqInnerData];
if (dataWithPadding.length > 144) {
return nil;
}
if (dataWithPadding.length != 192) {
int originalLength = (int)dataWithPadding.length;
int numPaddingBytes = 192 - originalLength;
[dataWithPadding setLength:192];
int randomResult = SecRandomCopyBytes(kSecRandomDefault, numPaddingBytes, ((uint8_t *)dataWithPadding.mutableBytes) + originalLength);
if (randomResult != errSecSuccess) {
return nil;
}
}
NSData *dataWithPaddingReversed = reversedBytes(dataWithPadding);
while (true) {
int randomResult = 0;
NSMutableData *tempKey = [[NSMutableData alloc] initWithLength:32];
randomResult = SecRandomCopyBytes(kSecRandomDefault, tempKey.length, tempKey.mutableBytes);
if (randomResult != errSecSuccess) {
return nil;
}
NSMutableData *tempKeyAndDataWithPadding = [[NSMutableData alloc] init];
[tempKeyAndDataWithPadding appendData:tempKey];
[tempKeyAndDataWithPadding appendData:dataWithPadding];
NSMutableData *dataWithHash = [[NSMutableData alloc] init];
[dataWithHash appendData:dataWithPaddingReversed];
[dataWithHash appendData:MTSha256(tempKeyAndDataWithPadding)];
if (dataWithHash.length != 224) {
return nil;
}
NSMutableData *zeroIv = [[NSMutableData alloc] initWithLength:32];
memset(zeroIv.mutableBytes, 0, zeroIv.length);
NSData *aesEncrypted = MTAesEncrypt(dataWithHash, tempKey, zeroIv);
if (aesEncrypted == nil) {
return nil;
}
NSData *shaAesEncrypted = MTSha256(aesEncrypted);
NSMutableData *tempKeyXor = [[NSMutableData alloc] initWithLength:tempKey.length];
if (tempKeyXor.length != shaAesEncrypted.length) {
return nil;
}
for (NSUInteger i = 0; i < tempKey.length; i++) {
((uint8_t *)tempKeyXor.mutableBytes)[i] = ((uint8_t *)tempKey.bytes)[i] ^ ((uint8_t *)shaAesEncrypted.bytes)[i];
}
NSMutableData *keyAesEncrypted = [[NSMutableData alloc] init];
[keyAesEncrypted appendData:tempKeyXor];
[keyAesEncrypted appendData:aesEncrypted];
if (keyAesEncrypted.length != 256) {
return nil;
}
id<MTBignumContext> bignumContext = [encryptionProvider createBignumContext];
if (bignumContext == nil) {
return nil;
}
id<MTRsaPublicKey> rsaPublicKey = [encryptionProvider parseRSAPublicKey:publicKey];
if (rsaPublicKey == nil) {
return nil;
}
id<MTBignum> rsaModule = [bignumContext rsaGetN:rsaPublicKey];
if (rsaModule == nil) {
return nil;
}
id<MTBignum> bignumKeyAesEncrypted = [bignumContext create];
if (bignumKeyAesEncrypted == nil) {
return nil;
}
[bignumContext assignBinTo:bignumKeyAesEncrypted value:keyAesEncrypted];
int compareResult = [bignumContext compare:rsaModule with:bignumKeyAesEncrypted];
if (compareResult <= 0) {
continue;
}
NSData *encryptedData = [encryptionProvider rsaEncryptWithPublicKey:publicKey data:keyAesEncrypted];
NSMutableData *paddedEncryptedData = [[NSMutableData alloc] init];
[paddedEncryptedData appendData:encryptedData];
while (paddedEncryptedData.length < 256) {
uint8_t zero = 0;
[paddedEncryptedData replaceBytesInRange:NSMakeRange(0, 0) withBytes:&zero length:1];
}
if (paddedEncryptedData.length != 256) {
return nil;
}
return paddedEncryptedData;
}
}
- (void)mtProto:(MTProto *)mtProto receivedMessage:(MTIncomingMessage *)message authInfoSelector:(MTDatacenterAuthInfoSelector)authInfoSelector networkType:(int32_t)networkType
{
if (_stage == MTDatacenterAuthStagePQ && [message.body isKindOfClass:[MTResPqMessage class]])
{
MTResPqMessage *resPqMessage = message.body;
if ([_nonce isEqualToData:resPqMessage.nonce])
{
MTDatacenterAuthPublicKey *publicKey = selectPublicKey(_encryptionProvider, resPqMessage.serverPublicKeyFingerprints, _publicKeys);
if (publicKey == nil && mtProto.cdn && resPqMessage.serverPublicKeyFingerprints.count == 1 && _publicKeys.count == 1) {
publicKey = _publicKeys[0];
}
if (publicKey == nil)
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p couldn't find valid server public key]", self);
}
[self reset:mtProto];
}
else
{
NSData *pqBytes = resPqMessage.pq;
uint64_t pq = 0;
for (int i = 0; i < (int)pqBytes.length; i++)
{
pq <<= 8;
pq |= ((uint8_t *)[pqBytes bytes])[i];
}
uint64_t factP = 0;
uint64_t factQ = 0;
if (!MTFactorize(pq, &factP, &factQ))
{
[self reset:mtProto];
return;
}
_serverNonce = resPqMessage.serverNonce;
NSMutableData *pBytes = [[NSMutableData alloc] init];
uint64_t p = factP;
do
{
[pBytes replaceBytesInRange:NSMakeRange(0, 0) withBytes:&p length:1];
p >>= 8;
} while (p > 0);
_dhP = pBytes;
NSMutableData *qBytes = [[NSMutableData alloc] init];
uint64_t q = factQ;
do
{
[qBytes replaceBytesInRange:NSMakeRange(0, 0) withBytes:&q length:1];
q >>= 8;
} while (q > 0);
_dhQ = qBytes;
_dhPublicKeyFingerprint = [publicKey fingerprintWithEncryptionProvider:_encryptionProvider];
uint8_t nonceBytes[32];
__unused int result = SecRandomCopyBytes(kSecRandomDefault, 32, nonceBytes);
_newNonce = [[NSData alloc] initWithBytes:nonceBytes length:32];
/*
p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;
*/
if (_tempAuth) {
MTBuffer *innerDataBuffer = [[MTBuffer alloc] init];
[innerDataBuffer appendInt32:(int32_t)0x3c6a84d4];
[innerDataBuffer appendTLBytes:pqBytes];
[innerDataBuffer appendTLBytes:_dhP];
[innerDataBuffer appendTLBytes:_dhQ];
[innerDataBuffer appendBytes:_nonce.bytes length:_nonce.length];
[innerDataBuffer appendBytes:_serverNonce.bytes length:_serverNonce.length];
[innerDataBuffer appendBytes:_newNonce.bytes length:_newNonce.length];
[innerDataBuffer appendInt32:mtProto.context.tempKeyExpiration];
NSData *innerDataBytes = innerDataBuffer.data;
NSData *encryptedData = nil;
encryptedData = encryptRSAModernPadding(_encryptionProvider, innerDataBytes, publicKey.publicKey);
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p encryptedData length %d]", self, (int)encryptedData.length);
}
_dhEncryptedData = encryptedData;
} else {
MTBuffer *innerDataBuffer = [[MTBuffer alloc] init];
[innerDataBuffer appendInt32:(int32_t)0x83c95aec];
[innerDataBuffer appendTLBytes:pqBytes];
[innerDataBuffer appendTLBytes:_dhP];
[innerDataBuffer appendTLBytes:_dhQ];
[innerDataBuffer appendBytes:_nonce.bytes length:_nonce.length];
[innerDataBuffer appendBytes:_serverNonce.bytes length:_serverNonce.length];
[innerDataBuffer appendBytes:_newNonce.bytes length:_newNonce.length];
NSData *innerDataBytes = innerDataBuffer.data;
NSData *encryptedData = nil;
encryptedData = encryptRSAModernPadding(_encryptionProvider, innerDataBytes, publicKey.publicKey);
_dhEncryptedData = encryptedData;
}
if (_dhEncryptedData == nil) {
_stage = MTDatacenterAuthStagePQ;
_currentStageMessageId = 0;
_currentStageMessageSeqNo = 0;
_currentStageTransactionId = nil;
[mtProto requestTransportTransaction];
} else {
_stage = MTDatacenterAuthStageReqDH;
_currentStageMessageId = 0;
_currentStageMessageSeqNo = 0;
_currentStageTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
}
}
else if (_stage == MTDatacenterAuthStageReqDH && [message.body isKindOfClass:[MTServerDhParamsMessage class]])
{
MTServerDhParamsMessage *serverDhParamsMessage = message.body;
if ([_nonce isEqualToData:serverDhParamsMessage.nonce] && [_serverNonce isEqualToData:serverDhParamsMessage.serverNonce])
{
if ([serverDhParamsMessage isKindOfClass:[MTServerDhParamsOkMessage class]])
{
NSMutableData *tmpAesKey = [[NSMutableData alloc] init];
NSMutableData *newNonceAndServerNonce = [[NSMutableData alloc] init];
[newNonceAndServerNonce appendData:_newNonce];
[newNonceAndServerNonce appendData:_serverNonce];
NSMutableData *serverNonceAndNewNonce = [[NSMutableData alloc] init];
[serverNonceAndNewNonce appendData:_serverNonce];
[serverNonceAndNewNonce appendData:_newNonce];
[tmpAesKey appendData:MTSha1(newNonceAndServerNonce)];
NSData *serverNonceAndNewNonceHash = MTSha1(serverNonceAndNewNonce);
NSData *serverNonceAndNewNonceHash0_12 = [[NSData alloc] initWithBytes:((uint8_t *)serverNonceAndNewNonceHash.bytes) length:12];
[tmpAesKey appendData:serverNonceAndNewNonceHash0_12];
NSMutableData *tmpAesIv = [[NSMutableData alloc] init];
NSData *serverNonceAndNewNonceHash12_8 = [[NSData alloc] initWithBytes:(((uint8_t *)serverNonceAndNewNonceHash.bytes) + 12) length:8];
[tmpAesIv appendData:serverNonceAndNewNonceHash12_8];
NSMutableData *newNonceAndNewNonce = [[NSMutableData alloc] init];
[newNonceAndNewNonce appendData:_newNonce];
[newNonceAndNewNonce appendData:_newNonce];
[tmpAesIv appendData:MTSha1(newNonceAndNewNonce)];
NSData *newNonce0_4 = [[NSData alloc] initWithBytes:((uint8_t *)_newNonce.bytes) length:4];
[tmpAesIv appendData:newNonce0_4];
NSData *answerWithHash = MTAesDecrypt(((MTServerDhParamsOkMessage *)serverDhParamsMessage).encryptedResponse, tmpAesKey, tmpAesIv);
NSData *answerHash = [[NSData alloc] initWithBytes:((uint8_t *)answerWithHash.bytes) length:20];
NSMutableData *answerData = [[NSMutableData alloc] initWithBytes:(((uint8_t *)answerWithHash.bytes) + 20) length:(answerWithHash.length - 20)];
bool hashVerified = false;
for (int i = 0; i < 16; i++)
{
NSData *computedAnswerHash = MTSha1(answerData);
if ([computedAnswerHash isEqualToData:answerHash])
{
hashVerified = true;
break;
}
[answerData replaceBytesInRange:NSMakeRange(answerData.length - 1, 1) withBytes:NULL length:0];
}
if (!hashVerified)
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p couldn't decode DH params]", self);
}
[self reset:mtProto];
return;
}
MTServerDhInnerDataMessage *dhInnerData = [MTInternalMessageParser parseMessage:answerData];
if (![dhInnerData isKindOfClass:[MTServerDhInnerDataMessage class]])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p couldn't parse decoded DH params]", self);
}
[self reset:mtProto];
return;
}
if (![_nonce isEqualToData:dhInnerData.nonce])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH nonce]", self);
}
[self reset:mtProto];
return;
}
if (![_serverNonce isEqualToData:dhInnerData.serverNonce])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH server nonce]", self);
}
[self reset:mtProto];
return;
}
int32_t innerDataG = dhInnerData.g;
if (innerDataG < 0 || !MTCheckIsSafeG((unsigned int)innerDataG))
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g]", self);
}
[self reset:mtProto];
return;
}
NSData *innerDataGA = dhInnerData.gA;
NSData *innerDataDhPrime = dhInnerData.dhPrime;
if (!MTCheckIsSafeGAOrB(_encryptionProvider, innerDataGA, innerDataDhPrime))
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g_a]", self);
}
[self reset:mtProto];
return;
}
if (!MTCheckMod(_encryptionProvider, innerDataDhPrime, (unsigned int)innerDataG, mtProto.context.keychain))
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g (2)]", self);
}
[self reset:mtProto];
return;
}
if (!MTCheckIsSafePrime(_encryptionProvider, innerDataDhPrime, mtProto.context.keychain))
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH prime]", self);
}
[self reset:mtProto];
return;
}
uint8_t bBytes[256];
__unused int result = SecRandomCopyBytes(kSecRandomDefault, 256, bBytes);
NSData *b = [[NSData alloc] initWithBytes:bBytes length:256];
int32_t tmpG = innerDataG;
tmpG = (int32_t)OSSwapInt32(tmpG);
NSData *g = [[NSData alloc] initWithBytes:&tmpG length:4];
NSData *g_b = MTExp(_encryptionProvider, g, b, innerDataDhPrime);
NSData *authKey = MTExp(_encryptionProvider, innerDataGA, b, innerDataDhPrime);
NSData *authKeyHash = MTSha1(authKey);
int64_t authKeyId = 0;
memcpy(&authKeyId, (((uint8_t *)authKeyHash.bytes) + authKeyHash.length - 8), 8);
NSMutableData *serverSaltData = [[NSMutableData alloc] init];
for (int i = 0; i < 8; i++)
{
int8_t a = ((int8_t *)_newNonce.bytes)[i];
int8_t b = ((int8_t *)_serverNonce.bytes)[i];
int8_t x = a ^ b;
[serverSaltData appendBytes:&x length:1];
}
int32_t validUntilTimestamp = ((int32_t)([NSDate date].timeIntervalSince1970)) + mtProto.context.tempKeyExpiration;
_authKey = [[MTDatacenterAuthKey alloc] initWithAuthKey:authKey authKeyId:authKeyId validUntilTimestamp:validUntilTimestamp notBound:_tempAuth];
MTBuffer *clientDhInnerDataBuffer = [[MTBuffer alloc] init];
[clientDhInnerDataBuffer appendInt32:(int32_t)0x6643b654];
[clientDhInnerDataBuffer appendBytes:_nonce.bytes length:_nonce.length];
[clientDhInnerDataBuffer appendBytes:_serverNonce.bytes length:_serverNonce.length];
[clientDhInnerDataBuffer appendInt64:0];
[clientDhInnerDataBuffer appendTLBytes:g_b];
NSData *clientInnerDataBytes = clientDhInnerDataBuffer.data;
NSMutableData *clientDataWithHash = [[NSMutableData alloc] init];
[clientDataWithHash appendData:MTSha1(clientInnerDataBytes)];
[clientDataWithHash appendData:clientInnerDataBytes];
while (clientDataWithHash.length % 16 != 0)
{
uint8_t randomByte = 0;
arc4random_buf(&randomByte, 1);
[clientDataWithHash appendBytes:&randomByte length:1];
}
_encryptedClientData = MTAesEncrypt(clientDataWithHash, tmpAesKey, tmpAesIv);
_stage = MTDatacenterAuthStageKeyVerification;
_currentStageMessageId = 0;
_currentStageMessageSeqNo = 0;
_currentStageTransactionId = nil;
[mtProto requestTransportTransaction];
}
else
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p couldn't set DH params]", self);
}
[self reset:mtProto];
}
}
}
else if (_stage == MTDatacenterAuthStageKeyVerification && [message.body isKindOfClass:[MTSetClientDhParamsResponseMessage class]])
{
MTSetClientDhParamsResponseMessage *setClientDhParamsResponseMessage = message.body;
if ([_nonce isEqualToData:setClientDhParamsResponseMessage.nonce] && [_serverNonce isEqualToData:setClientDhParamsResponseMessage.serverNonce])
{
NSData *authKeyAuxHashFull = MTSha1(_authKey.authKey);
NSData *authKeyAuxHash = [[NSData alloc] initWithBytes:((uint8_t *)authKeyAuxHashFull.bytes) length:8];
NSMutableData *newNonce1 = [[NSMutableData alloc] init];
[newNonce1 appendData:_newNonce];
uint8_t tmp1 = 1;
[newNonce1 appendBytes:&tmp1 length:1];
[newNonce1 appendData:authKeyAuxHash];
NSData *newNonceHash1Full = MTSha1(newNonce1);
NSData *newNonceHash1 = [[NSData alloc] initWithBytes:(((uint8_t *)newNonceHash1Full.bytes) + newNonceHash1Full.length - 16) length:16];
NSMutableData *newNonce2 = [[NSMutableData alloc] init];
[newNonce2 appendData:_newNonce];
uint8_t tmp2 = 2;
[newNonce2 appendBytes:&tmp2 length:1];
[newNonce2 appendData:authKeyAuxHash];
NSData *newNonceHash2Full = MTSha1(newNonce2);
NSData *newNonceHash2 = [[NSData alloc] initWithBytes:(((uint8_t *)newNonceHash2Full.bytes) + newNonceHash2Full.length - 16) length:16];
NSMutableData *newNonce3 = [[NSMutableData alloc] init];
[newNonce3 appendData:_newNonce];
uint8_t tmp3 = 3;
[newNonce3 appendBytes:&tmp3 length:1];
[newNonce3 appendData:authKeyAuxHash];
NSData *newNonceHash3Full = MTSha1(newNonce3);
NSData *newNonceHash3 = [[NSData alloc] initWithBytes:(((uint8_t *)newNonceHash3Full.bytes) + newNonceHash3Full.length - 16) length:16];
if ([setClientDhParamsResponseMessage isKindOfClass:[MTSetClientDhParamsResponseOkMessage class]])
{
if (![newNonceHash1 isEqualToData:((MTSetClientDhParamsResponseOkMessage *)setClientDhParamsResponseMessage).nextNonceHash1])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH answer nonce hash 1]", self);
}
[self reset:mtProto];
}
else
{
_stage = MTDatacenterAuthStageDone;
_currentStageMessageId = 0;
_currentStageMessageSeqNo = 0;
_currentStageTransactionId = nil;
id<MTDatacenterAuthMessageServiceDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(authMessageServiceCompletedWithAuthKey:timestamp:)])
[delegate authMessageServiceCompletedWithAuthKey:_authKey timestamp:message.messageId];
}
}
else if ([setClientDhParamsResponseMessage isKindOfClass:[MTSetClientDhParamsResponseRetryMessage class]])
{
if (![newNonceHash2 isEqualToData:((MTSetClientDhParamsResponseRetryMessage *)setClientDhParamsResponseMessage).nextNonceHash2])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH answer nonce hash 2]", self);
}
[self reset:mtProto];
}
else
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p retry DH]", self);
}
[self reset:mtProto];
}
}
else if ([setClientDhParamsResponseMessage isKindOfClass:[MTSetClientDhParamsResponseFailMessage class]])
{
if (![newNonceHash3 isEqualToData:((MTSetClientDhParamsResponseFailMessage *)setClientDhParamsResponseMessage).nextNonceHash3])
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH answer nonce hash 3]", self);
}
[self reset:mtProto];
}
else
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p server rejected DH params]", self);
}
[self reset:mtProto];
}
}
else
{
if (MTLogEnabled()) {
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH params response]", self);
}
[self reset:mtProto];
}
}
}
}
- (void)mtProto:(MTProto *)mtProto protocolErrorReceived:(int32_t)__unused errorCode
{
[self reset:mtProto];
}
- (void)mtProto:(MTProto *)mtProto transactionsMayHaveFailed:(NSArray *)transactionIds
{
if (_currentStageTransactionId != nil && [transactionIds containsObject:_currentStageTransactionId])
{
_currentStageTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
- (void)mtProtoAllTransactionsMayHaveFailed:(MTProto *)mtProto
{
if (_currentStageTransactionId != nil)
{
_currentStageTransactionId = nil;
[mtProto requestTransportTransaction];
}
}
@end
@@ -0,0 +1,49 @@
#import <MtProtoKit/MTDatacenterSaltInfo.h>
@implementation MTDatacenterSaltInfo
- (instancetype)initWithSalt:(int64_t)salt firstValidMessageId:(int64_t)firstValidMessageId lastValidMessageId:(int64_t)lastValidMessageId
{
self = [super init];
if (self != nil)
{
_salt = salt;
_firstValidMessageId = firstValidMessageId;
_lastValidMessageId = lastValidMessageId;
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self != nil)
{
_salt = [aDecoder decodeInt64ForKey:@"salt"];
_firstValidMessageId = [aDecoder decodeInt64ForKey:@"firstValidMessageId"];
_lastValidMessageId = [aDecoder decodeInt64ForKey:@"lastValidMessageId"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeInt64:_salt forKey:@"salt"];
[aCoder encodeInt64:_firstValidMessageId forKey:@"firstValidMessageId"];
[aCoder encodeInt64:_lastValidMessageId forKey:@"lastValidMessageId"];
}
- (int64_t)validMessageCountAfterId:(int64_t)messageId
{
if (messageId < _firstValidMessageId)
return 0;
return MAX(0, _lastValidMessageId - messageId);
}
- (bool)isValidFutureSaltForMessageId:(int64_t)messageId
{
return _lastValidMessageId > messageId;
}
@end
@@ -0,0 +1,190 @@
#import <MtProtoKit/MTDatacenterTransferAuthAction.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTSerialization.h>
#import <MtProtoKit/MTProto.h>
#import <MtProtoKit/MTRequestMessageService.h>
#import <MtProtoKit/MTRequest.h>
#import "MTBuffer.h"
@interface MTDatacenterTransferAuthAction () <MTContextChangeListener>
{
id _authToken;
MTProto *_sourceDatacenterMtProto;
NSInteger _destinationDatacenterId;
MTProto *_destinationDatacenterMtProto;
__weak MTContext *_context;
}
@end
@implementation MTDatacenterTransferAuthAction
- (void)dealloc
{
[self cleanup];
}
- (void)cleanup
{
MTContext *context = _context;
[context removeChangeListener:self];
[_sourceDatacenterMtProto stop];
_sourceDatacenterMtProto = nil;
[_destinationDatacenterMtProto stop];
_destinationDatacenterMtProto = nil;
}
- (void)execute:(MTContext *)context masterDatacenterId:(NSInteger)masterDatacenterId destinationDatacenterId:(NSInteger)destinationDatacenterId authToken:(id)authToken
{
_destinationDatacenterId = destinationDatacenterId;
_context = context;
_authToken = authToken;
if (_destinationDatacenterId != 0 && context != nil && _authToken != nil)
{
if ([_authToken isEqual:[context authTokenForDatacenterWithId:_destinationDatacenterId]])
[self complete];
else
[self beginTransferFromDatacenterId:masterDatacenterId];
}
else
[self fail];
}
- (void)contextDatacenterAuthTokenUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId authToken:(id)authToken
{
MTContext *currentContext = _context;
if (currentContext == nil || context != currentContext)
return;
if (authToken != nil && [_authToken isEqual:authToken])
{
if (datacenterId == _destinationDatacenterId)
[self complete];
else
[self beginTransferFromDatacenterId:datacenterId];
}
}
- (void)beginTransferFromDatacenterId:(NSInteger)sourceDatacenterId
{
MTContext *context = _context;
if (context == nil)
{
[self fail];
return;
}
_sourceDatacenterMtProto = [[MTProto alloc] initWithContext:context datacenterId:sourceDatacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
_sourceDatacenterMtProto.useTempAuthKeys = context.useTempAuthKeys;
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
requestService.forceBackgroundRequests = true;
[_sourceDatacenterMtProto addMessageService:requestService];
[_sourceDatacenterMtProto resume];
MTRequest *request = [[MTRequest alloc] init];
NSData *exportAuthRequestData = nil;
MTExportAuthorizationResponseParser responseParser = [[context.serialization exportAuthorization:(int32_t)_destinationDatacenterId data:&exportAuthRequestData] copy];
[request setPayload:exportAuthRequestData metadata:@"exportAuthorization" shortMetadata:@"exportAuthorization" responseParser:responseParser];
__weak MTDatacenterTransferAuthAction *weakSelf = self;
[request setCompleted:^(MTExportedAuthorizationData *result, __unused MTRequestResponseInfo *info, id error)
{
__strong MTDatacenterTransferAuthAction *strongSelf = weakSelf;
if (strongSelf == nil)
return;
if (error == nil)
{
[strongSelf beginTransferWithId:result.authorizationId data:result.authorizationBytes];
}
else
[strongSelf fail];
}];
[requestService addRequest:request];
}
- (void)beginTransferWithId:(int64_t)dataId data:(NSData *)authData
{
[_sourceDatacenterMtProto stop];
_sourceDatacenterMtProto = nil;
MTContext *context = _context;
_destinationDatacenterMtProto = [[MTProto alloc] initWithContext:context datacenterId:_destinationDatacenterId usageCalculationInfo:nil requiredAuthToken:nil authTokenMasterDatacenterId:0];
_destinationDatacenterMtProto.canResetAuthData = true;
_destinationDatacenterMtProto.useTempAuthKeys = context.useTempAuthKeys;
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
requestService.forceBackgroundRequests = true;
[_destinationDatacenterMtProto addMessageService:requestService];
[_destinationDatacenterMtProto resume];
MTRequest *request = [[MTRequest alloc] init];
NSData *importAuthRequestData = [_context.serialization importAuthorization:dataId bytes:authData];
[request setPayload:importAuthRequestData metadata:@"importAuthorization" shortMetadata:@"importAuthorization" responseParser:^id (NSData *data)
{
return @true;
}];
NSInteger destinationDatacenterId = _destinationDatacenterId;
id authToken = _authToken;
__weak MTDatacenterTransferAuthAction *weakSelf = self;
[request setCompleted:^(__unused id result, __unused MTRequestResponseInfo *info, id error)
{
__strong MTDatacenterTransferAuthAction *strongSelf = weakSelf;
if (strongSelf == nil)
return;
if (error == nil)
{
[context updateAuthTokenForDatacenterWithId:destinationDatacenterId authToken:authToken];
[strongSelf complete];
}
else
[strongSelf fail];
}];
[requestService addRequest:request];
}
- (void)cancel
{
[self cleanup];
[self fail];
}
- (void)complete
{
id<MTDatacenterTransferAuthActionDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(datacenterTransferAuthActionCompleted:)])
[delegate datacenterTransferAuthActionCompleted:self];
}
- (void)fail
{
id<MTDatacenterTransferAuthActionDelegate> delegate = _delegate;
if ([delegate respondsToSelector:@selector(datacenterTransferAuthActionCompleted:)])
[delegate datacenterTransferAuthActionCompleted:self];
}
@end
@@ -0,0 +1,18 @@
#import <MtProtoKit/MTDatacenterVerificationData.h>
@implementation MTDatacenterVerificationData
- (instancetype _Nonnull)initWithDatacenterId:(NSInteger)datacenterId isTestingEnvironment:(bool)isTestingEnvironment {
self = [super init];
if (self != nil) {
_datacenterId = datacenterId;
_isTestingEnvironment = isTestingEnvironment;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"datacenterId: %d, isTestingEnvironment: %d", (int)_datacenterId, _isTestingEnvironment ? 1 : 0];
}
@end
@@ -0,0 +1,29 @@
#import <Foundation/Foundation.h>
@interface MTDestroySessionResponseMessage : NSObject
@end
@interface MTDestroySessionResponseOkMessage : MTDestroySessionResponseMessage
@property (nonatomic, readonly) int64_t sessionId;
- (instancetype)initWithSessionId:(int64_t)sessionId;
@end
@interface MTDestroySessionResponseNoneMessage : MTDestroySessionResponseMessage
@property (nonatomic, readonly) int64_t sessionId;
- (instancetype)initWithSessionId:(int64_t)sessionId;
@end
@interface MTDestroySessionMultipleResponseMessage : MTDestroySessionResponseMessage
@property (nonatomic, strong, readonly) NSData *responsesData;
- (instancetype)initWithResponses:(NSData *)responsesData;
@end
@@ -0,0 +1,47 @@
#import "MTDestroySessionResponseMessage.h"
@implementation MTDestroySessionResponseMessage
@end
@implementation MTDestroySessionResponseOkMessage
- (instancetype)initWithSessionId:(int64_t)sessionId
{
self = [super init];
if (self != nil)
{
_sessionId = sessionId;
}
return self;
}
@end
@implementation MTDestroySessionResponseNoneMessage
- (instancetype)initWithSessionId:(int64_t)sessionId
{
self = [super init];
if (self != nil)
{
_sessionId = sessionId;
}
return self;
}
@end
@implementation MTDestroySessionMultipleResponseMessage
- (instancetype)initWithResponses:(NSData *)responsesData
{
self = [super init];
if (self != nil)
{
_responsesData = responsesData;
}
return self;
}
@end
@@ -0,0 +1,20 @@
#import <Foundation/Foundation.h>
@class MTContext;
@class MTDatacenterAddress;
@class MTSignal;
@class MTDatacenterAuthKey;
typedef struct {
uint8_t nonce[16];
} MTPayloadData;
@interface MTDiscoverConnectionSignals : NSObject
+ (NSData * _Nonnull)payloadData:(MTPayloadData * _Nonnull)outPayloadData context:(MTContext * _Nonnull)context address:(MTDatacenterAddress * _Nonnull)address;
+ (MTSignal * _Nonnull)discoverSchemeWithContext:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId addressList:(NSArray * _Nonnull)addressList media:(bool)media isProxy:(bool)isProxy;
+ (MTSignal * _Nonnull)checkIfAuthKeyRemovedWithContext:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId authKey:(MTDatacenterAuthKey * _Nonnull)authKey;
@end
@@ -0,0 +1,267 @@
#import "MTDiscoverConnectionSignals.h"
#import "MTTcpConnection.h"
#import <MtProtoKit/MTTransportScheme.h>
#import <MtProtoKit/MTTcpTransport.h>
#import <MtProtoKit/MTQueue.h>
#import <MtProtoKit/MTDatacenterAddress.h>
#import <MtProtoKit/MTDisposable.h>
#import <MtProtoKit/MTSignal.h>
#import <MtProtoKit/MTAtomic.h>
#import <MtProtoKit/MTContext.h>
#import <MtProtoKit/MTApiEnvironment.h>
#import <MtProtoKit/MTLogging.h>
#import <MtProtoKit/MTDatacenterAuthAction.h>
#import <netinet/in.h>
#import <arpa/inet.h>
@implementation MTDiscoverConnectionSignals
+ (NSData *)payloadData:(MTPayloadData *)outPayloadData context:(MTContext *)context address:(MTDatacenterAddress *)address {
uint8_t reqPqBytes[] = {
0, 0, 0, 0, 0, 0, 0, 0, // zero * 8
0, 0, 0, 0, 0, 0, 0, 0, // message id
20, 0, 0, 0, // message length
0xf1, 0x8e, 0x7e, 0xbe, // req_pq_multi
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // nonce
};
MTPayloadData payloadData;
arc4random_buf(&payloadData.nonce, 16);
if (outPayloadData)
*outPayloadData = payloadData;
int64_t messageId = (int64_t)([[NSDate date] timeIntervalSince1970] * 4294967296);
memcpy(reqPqBytes + 8, &messageId, 8);
memcpy(reqPqBytes + 8 + 8 + 4 + 4, payloadData.nonce, 16);
NSMutableData *data = [[NSMutableData alloc] initWithBytes:reqPqBytes length:sizeof(reqPqBytes)];
NSData *secret = address.secret;
if (context.apiEnvironment.socksProxySettings != nil) {
if (context.apiEnvironment.socksProxySettings.secret != nil) {
secret = context.apiEnvironment.socksProxySettings.secret;
}
}
bool extendedPadding = false;
if (secret != nil) {
MTProxySecret *parsedSecret = [MTProxySecret parseData:secret];
if ([parsedSecret isKindOfClass:[MTProxySecretType1 class]] || [parsedSecret isKindOfClass:[MTProxySecretType2 class]]) {
extendedPadding = true;
}
}
if (extendedPadding) {
uint32_t paddingSize = arc4random_uniform(128);
if (paddingSize != 0) {
uint8_t padding[128];
arc4random_buf(padding, paddingSize);
[data appendBytes:padding length:paddingSize];
}
}
return data;
}
+ (bool)isResponseValid:(NSData *)data payloadData:(MTPayloadData)payloadData {
if (data.length >= 84) {
uint8_t zero[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t resPq[] = { 0x63, 0x24, 0x16, 0x05 };
if (memcmp((uint8_t * const)data.bytes, zero, 8) == 0 && memcmp(((uint8_t * const)data.bytes) + 20, resPq, 4) == 0 && memcmp(((uint8_t * const)data.bytes) + 24, payloadData.nonce, 16) == 0) {
return true;
}
}
return false;
}
+ (bool)isIpv6:(NSString *)ip
{
const char *utf8 = [ip UTF8String];
int success;
struct in6_addr dst6;
success = inet_pton(AF_INET6, utf8, &dst6);
return success == 1;
}
+ (MTSignal *)tcpConnectionWithContext:(MTContext *)context datacenterId:(NSUInteger)datacenterId address:(MTDatacenterAddress *)address;
{
return [[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber)
{
MTPayloadData payloadData;
NSData *data = [self payloadData:&payloadData context:context address:address];
MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:context datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:address media:false] interface:nil usageCalculationInfo:nil getLogPrefix:nil];
__weak MTTcpConnection *weakConnection = connection;
connection.connectionOpened = ^
{
__strong MTTcpConnection *strongConnection = weakConnection;
if (strongConnection != nil)
[strongConnection sendDatas:@[data] completion:nil requestQuickAck:false expectDataInResponse:true];
};
MTAtomic *processedData = [[MTAtomic alloc] initWithValue:@false];
connection.connectionReceivedData = ^(NSData *data)
{
[processedData swap:@true];
if ([self isResponseValid:data payloadData:payloadData])
{
if (MTLogEnabled()) {
MTLog(@"success tcp://%@:%d", address.ip, (int)address.port);
}
[subscriber putCompletion];
}
else
{
if (MTLogEnabled()) {
MTLog(@"failed tcp://%@:%d (invalid response)", address.ip, (int)address.port);
}
[subscriber putError:nil];
}
};
connection.connectionClosed = ^
{
__block bool received = false;
[processedData with:^id (NSNumber *value) {
received = [value boolValue];
return nil;
}];
if (!received) {
if (MTLogEnabled()) {
MTLog(@"failed tcp://%@:%d (disconnected)", address.ip, (int)address.port);
}
[subscriber putError:nil];
}
};
if (MTLogEnabled()) {
MTLog(@"trying tcp://%@:%d", address.ip, (int)address.port);
}
[connection start];
return [[MTBlockDisposable alloc] initWithBlock:^
{
[connection stop];
}];
}] startOn:[MTTcpConnection tcpQueue]];
}
+ (MTSignal *)discoverSchemeWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId addressList:(NSArray *)addressList media:(bool)media isProxy:(bool)isProxy
{
NSMutableArray *bestAddressList = [[NSMutableArray alloc] init];
for (MTDatacenterAddress *address in addressList)
{
if (media == address.preferForMedia && isProxy == address.preferForProxy) {
[bestAddressList addObject:address];
}
}
if (bestAddressList.count == 0 && media)
[bestAddressList addObjectsFromArray:addressList];
NSMutableArray *bestTcp4Signals = [[NSMutableArray alloc] init];
NSMutableArray *bestTcp6Signals = [[NSMutableArray alloc] init];
NSMutableArray *bestHttpSignals = [[NSMutableArray alloc] init];
NSMutableDictionary *tcpIpsByPort = [[NSMutableDictionary alloc] init];
for (MTDatacenterAddress *address in bestAddressList) {
NSMutableSet *ips = tcpIpsByPort[@(address.port)];
if (ips == nil) {
ips = [[NSMutableSet alloc] init];
tcpIpsByPort[@(address.port)] = ips;
}
[ips addObject:address.ip];
}
for (MTDatacenterAddress *address in bestAddressList) {
MTTransportScheme *tcpTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:address media:media];
if ([self isIpv6:address.ip])
{
MTSignal *signal = [[[[self tcpConnectionWithContext:context datacenterId:datacenterId address:address] then:[MTSignal single:tcpTransportScheme]] timeout:5.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal fail:nil]] catch:^MTSignal *(__unused id error)
{
return [MTSignal complete];
}];
[bestTcp6Signals addObject:signal];
}
else
{
MTSignal *tcpConnectionWithTimeout = [[[self tcpConnectionWithContext:context datacenterId:datacenterId address:address] then:[MTSignal single:tcpTransportScheme]] timeout:5.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal fail:nil]];
MTSignal *signal = [tcpConnectionWithTimeout catch:^MTSignal *(__unused id error)
{
return [MTSignal complete];
}];
[bestTcp4Signals addObject:signal];
NSArray *alternatePorts = @[@80, @5222];
for (NSNumber *nPort in alternatePorts) {
NSSet *ipsWithPort = tcpIpsByPort[nPort];
if (![ipsWithPort containsObject:address.ip]) {
MTDatacenterAddress *portAddress = [[MTDatacenterAddress alloc] initWithIp:address.ip port:[nPort intValue] preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp cdn:address.cdn preferForProxy:address.preferForProxy secret:address.secret];
MTTransportScheme *tcpPortTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:portAddress media:media];
MTSignal *tcpConnectionWithTimeout = [[[self tcpConnectionWithContext:context datacenterId:datacenterId address:portAddress] then:[MTSignal single:tcpPortTransportScheme]] timeout:5.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal fail:nil]];
tcpConnectionWithTimeout = [tcpConnectionWithTimeout mapToSignal:^(id next) {
return [[MTSignal single:next] delay:5.0 onQueue:[MTQueue concurrentDefaultQueue]];
}];
MTSignal *signal = [tcpConnectionWithTimeout catch:^MTSignal *(__unused id error) {
return [MTSignal complete];
}];
[bestTcp4Signals addObject:signal];
}
}
}
}
MTSignal *repeatDelaySignal = [[MTSignal complete] delay:1.0 onQueue:[MTQueue concurrentDefaultQueue]];
MTSignal *optimalDelaySignal = [[MTSignal complete] delay:30.0 onQueue:[MTQueue concurrentDefaultQueue]];
MTSignal *firstTcp4Match = [[[[MTSignal mergeSignals:bestTcp4Signals] then:repeatDelaySignal] restart] take:1];
MTSignal *firstTcp6Match = [[[[MTSignal mergeSignals:bestTcp6Signals] then:repeatDelaySignal] restart] take:1];
MTSignal *firstHttpMatch = [[[[MTSignal mergeSignals:bestHttpSignals] then:repeatDelaySignal] restart] take:1];
MTSignal *optimalTcp4Match = [[[[MTSignal mergeSignals:bestTcp4Signals] then:optimalDelaySignal] restart] take:1];
MTSignal *optimalTcp6Match = [[[[MTSignal mergeSignals:bestTcp6Signals] then:optimalDelaySignal] restart] take:1];
MTSignal *anySignal = [[MTSignal mergeSignals:@[firstTcp4Match, firstTcp6Match, firstHttpMatch]] take:1];
MTSignal *optimalSignal = [[MTSignal mergeSignals:@[optimalTcp4Match, optimalTcp6Match]] take:1];
MTSignal *signal = [anySignal mapToSignal:^MTSignal *(MTTransportScheme *scheme)
{
if (![scheme isOptimal])
{
return [[MTSignal single:scheme] then:[optimalSignal delay:5.0 onQueue:[MTQueue concurrentDefaultQueue]]];
}
else
return [MTSignal single:scheme];
}];
return [signal catch:^MTSignal *(id error) {
return [MTSignal complete];
}];
}
+ (MTSignal * _Nonnull)checkIfAuthKeyRemovedWithContext:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId authKey:(MTDatacenterAuthKey *)authKey {
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
MTMetaDisposable *disposable = [[MTMetaDisposable alloc] init];
[[MTContext contextQueue] dispatchOnQueue:^{
MTDatacenterAuthAction *action = [[MTDatacenterAuthAction alloc] initWithAuthKeyInfoSelector:MTDatacenterAuthInfoSelectorEphemeralMain isCdn:false skipBind:false completion:^(__unused MTDatacenterAuthAction *action, bool success) {
[subscriber putNext:@(!success)];
[subscriber putCompletion];
}];
[action execute:context datacenterId:datacenterId];
[disposable setDisposable:[[MTBlockDisposable alloc] initWithBlock:^{
[action cancel];
}]];
}];
return disposable;
}];
}
@end
@@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
@class MTContext;
@class MTDiscoverDatacenterAddressAction;
@protocol MTDiscoverDatacenterAddressActionDelegate <NSObject>
- (void)discoverDatacenterAddressActionCompleted:(MTDiscoverDatacenterAddressAction *)action;
@end
@interface MTDiscoverDatacenterAddressAction : NSObject
@property (nonatomic, weak) id<MTDiscoverDatacenterAddressActionDelegate> delegate;
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId;
- (void)cancel;
@end

Some files were not shown because too many files have changed in this diff Show More