mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add 'submodules/MtProtoKit/' from commit '14ab734b977fd4f1686a2a13415f6a4c9b9fdd6d'
git-subtree-dir: submodules/MtProtoKit git-subtree-mainline: 3b155750f5a4894ff3dedf1860a37e94e0ea9571 git-subtree-split: 14ab734b977fd4f1686a2a13415f6a4c9b9fdd6d
This commit is contained in:
commit
373769682e
25
submodules/MtProtoKit/.gitignore
vendored
Normal file
25
submodules/MtProtoKit/.gitignore
vendored
Normal 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/*
|
119
submodules/MtProtoKit/BUCK
Normal file
119
submodules/MtProtoKit/BUCK
Normal file
@ -0,0 +1,119 @@
|
||||
load('//tools:buck_utils.bzl', 'config_with_updated_linker_flags', 'combined_config', 'configs_with_config')
|
||||
load('//tools:buck_defs.bzl', 'SHARED_CONFIGS', 'EXTENSION_LIB_SPECIFIC_CONFIG')
|
||||
|
||||
genrule(
|
||||
name = 'openssl_libs',
|
||||
srcs = [
|
||||
'openssl/iOS/libcrypto.a',
|
||||
],
|
||||
bash = 'mkdir -p $OUT; cp $SRCS $OUT/',
|
||||
out = 'openssl_libs',
|
||||
visibility = [
|
||||
'//submodules/MtProtoKit:...',
|
||||
]
|
||||
)
|
||||
|
||||
apple_library(
|
||||
name = 'openssl',
|
||||
visibility = [
|
||||
'//submodules/MtProtoKit:MtProtoKit'
|
||||
],
|
||||
header_namespace = 'openssl',
|
||||
exported_headers = glob([
|
||||
'openssl/**/*.h',
|
||||
]),
|
||||
exported_linker_flags = [
|
||||
'-lcrypto',
|
||||
'-L$(location :openssl_libs)',
|
||||
],
|
||||
)
|
||||
|
||||
apple_library(
|
||||
name = 'MtProtoKit',
|
||||
srcs = glob([
|
||||
'*.m',
|
||||
'MtProtoKit/*.m',
|
||||
'thirdparty/AFNetworking/*.m',
|
||||
'thirdparty/AsyncSocket/*.m',
|
||||
]),
|
||||
configs = configs_with_config(combined_config([SHARED_CONFIGS, EXTENSION_LIB_SPECIFIC_CONFIG])),
|
||||
headers = glob([
|
||||
'*.h',
|
||||
'MtProtoKit/*.h',
|
||||
'thirdparty/AFNetworking/*.h',
|
||||
'thirdparty/AsyncSocket/*.h',
|
||||
]),
|
||||
header_namespace = 'MtProtoKit',
|
||||
exported_headers = [
|
||||
'MtProtoKit/MTTime.h',
|
||||
'MtProtoKit/MTTimer.h',
|
||||
'MtProtoKit/MTLogging.h',
|
||||
'MtProtoKit/MTEncryption.h',
|
||||
'MtProtoKit/MTInternalId.h',
|
||||
'MtProtoKit/MTQueue.h',
|
||||
'MtProtoKit/MTOutputStream.h',
|
||||
'MtProtoKit/MTInputStream.h',
|
||||
'MtProtoKit/MTSerialization.h',
|
||||
'MtProtoKit/MTExportedAuthorizationData.h',
|
||||
'MtProtoKit/MTRpcError.h',
|
||||
'MtProtoKit/MTKeychain.h',
|
||||
'MtProtoKit/MTFileBasedKeychain.h',
|
||||
'MtProtoKit/MTContext.h',
|
||||
'MtProtoKit/MTTransportScheme.h',
|
||||
'MtProtoKit/MTDatacenterTransferAuthAction.h',
|
||||
'MtProtoKit/MTDatacenterAuthAction.h',
|
||||
'MtProtoKit/MTDatacenterAuthMessageService.h',
|
||||
'MtProtoKit/MTDatacenterAddress.h',
|
||||
'MtProtoKit/MTDatacenterAddressSet.h',
|
||||
'MtProtoKit/MTDatacenterAuthInfo.h',
|
||||
'MtProtoKit/MTDatacenterSaltInfo.h',
|
||||
'MtProtoKit/MTDatacenterAddressListData.h',
|
||||
'MtProtoKit/MTProto.h',
|
||||
'MtProtoKit/MTSessionInfo.h',
|
||||
'MtProtoKit/MTTimeFixContext.h',
|
||||
'MtProtoKit/MTPreparedMessage.h',
|
||||
'MtProtoKit/MTOutgoingMessage.h',
|
||||
'MtProtoKit/MTIncomingMessage.h',
|
||||
'MtProtoKit/MTMessageEncryptionKey.h',
|
||||
'MtProtoKit/MTMessageService.h',
|
||||
'MtProtoKit/MTMessageTransaction.h',
|
||||
'MtProtoKit/MTTimeSyncMessageService.h',
|
||||
'MtProtoKit/MTRequestMessageService.h',
|
||||
'MtProtoKit/MTRequest.h',
|
||||
'MtProtoKit/MTRequestContext.h',
|
||||
'MtProtoKit/MTRequestErrorContext.h',
|
||||
'MtProtoKit/MTDropResponseContext.h',
|
||||
'MtProtoKit/MTApiEnvironment.h',
|
||||
'MtProtoKit/MTResendMessageService.h',
|
||||
'MtProtoKit/MTNetworkAvailability.h',
|
||||
'MtProtoKit/MTTransport.h',
|
||||
'MtProtoKit/MTTransportTransaction.h',
|
||||
'MtProtoKit/MTTcpTransport.h',
|
||||
'MtProtoKit/MTHttpRequestOperation.h',
|
||||
'MTAtomic.h',
|
||||
'MTBag.h',
|
||||
'MTDisposable.h',
|
||||
'MTSubscriber.h',
|
||||
'MTSignal.h',
|
||||
'MTNetworkUsageCalculationInfo.h',
|
||||
'MTNetworkUsageManager.h',
|
||||
'MTBackupAddressSignals.h',
|
||||
'thirdparty/AFNetworking/AFURLConnectionOperation.h',
|
||||
'thirdparty/AFNetworking/AFHTTPRequestOperation.h',
|
||||
'MTProxyConnectivity.h',
|
||||
'MTGzip.h',
|
||||
'MTDatacenterVerificationData.h',
|
||||
'MTPKCS.h',
|
||||
],
|
||||
modular = True,
|
||||
compiler_flags = ['-w'],
|
||||
preprocessor_flags = ['-fobjc-arc'],
|
||||
visibility = ['PUBLIC'],
|
||||
deps = [
|
||||
':openssl',
|
||||
],
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/Security.framework',
|
||||
],
|
||||
)
|
12
submodules/MtProtoKit/MTAes.h
Normal file
12
submodules/MtProtoKit/MTAes.h
Normal file
@ -0,0 +1,12 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTEncryption.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTEncryption.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTEncryption.h>
|
||||
#endif
|
||||
|
||||
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);
|
316
submodules/MtProtoKit/MTAes.m
Normal file
316
submodules/MtProtoKit/MTAes.m
Normal file
@ -0,0 +1,316 @@
|
||||
#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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 && 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
|
11
submodules/MtProtoKit/MTAtomic.h
Normal file
11
submodules/MtProtoKit/MTAtomic.h
Normal file
@ -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
|
64
submodules/MtProtoKit/MTAtomic.m
Normal file
64
submodules/MtProtoKit/MTAtomic.m
Normal file
@ -0,0 +1,64 @@
|
||||
#import "MTAtomic.h"
|
||||
|
||||
#import <libkern/OSAtomic.h>
|
||||
|
||||
@interface MTAtomic ()
|
||||
{
|
||||
volatile OSSpinLock _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;
|
||||
OSSpinLockLock(&_lock);
|
||||
previousValue = _value;
|
||||
_value = newValue;
|
||||
OSSpinLockUnlock(&_lock);
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
- (id)value
|
||||
{
|
||||
id previousValue = nil;
|
||||
OSSpinLockLock(&_lock);
|
||||
previousValue = _value;
|
||||
OSSpinLockUnlock(&_lock);
|
||||
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
- (id)modify:(id (^)(id))f
|
||||
{
|
||||
id newValue = nil;
|
||||
OSSpinLockLock(&_lock);
|
||||
newValue = f(_value);
|
||||
_value = newValue;
|
||||
OSSpinLockUnlock(&_lock);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
- (id)with:(id (^)(id))f
|
||||
{
|
||||
id result = nil;
|
||||
OSSpinLockLock(&_lock);
|
||||
result = f(_value);
|
||||
OSSpinLockUnlock(&_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
10
submodules/MtProtoKit/MTBackupAddressSignals.h
Normal file
10
submodules/MtProtoKit/MTBackupAddressSignals.h
Normal file
@ -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;
|
||||
|
||||
@end
|
231
submodules/MtProtoKit/MTBackupAddressSignals.m
Normal file
231
submodules/MtProtoKit/MTBackupAddressSignals.m
Normal file
@ -0,0 +1,231 @@
|
||||
#import "MTBackupAddressSignals.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
# import <MTProtoKitDynamic/MTQueue.h>
|
||||
# import <MTProtoKitDynamic/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitDynamic/MTEncryption.h>
|
||||
# import <MTProtoKitDynamic/MTRequestMessageService.h>
|
||||
# import <MTProtoKitDynamic/MTRequest.h>
|
||||
# import <MTProtoKitDynamic/MTContext.h>
|
||||
# import <MTProtoKitDynamic/MTApiEnvironment.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitDynamic/MTProto.h>
|
||||
# import <MTProtoKitDynamic/MTSerialization.h>
|
||||
# import <MTProtoKitDynamic/MTLogging.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
# import <MTProtoKitMac/MTQueue.h>
|
||||
# import <MTProtoKitMac/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitMac/MTEncryption.h>
|
||||
# import <MTProtoKitMac/MTRequestMessageService.h>
|
||||
# import <MTProtoKitMac/MTRequest.h>
|
||||
# import <MTProtoKitMac/MTContext.h>
|
||||
# import <MTProtoKitMac/MTApiEnvironment.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitMac/MTProto.h>
|
||||
# import <MTProtoKitMac/MTSerialization.h>
|
||||
# import <MTProtoKitMac/MTLogging.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTSignal.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>
|
||||
#endif
|
||||
|
||||
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 {
|
||||
NSArray *hosts = @[
|
||||
@"google.com",
|
||||
@"www.google.com",
|
||||
@"google.ru"
|
||||
];
|
||||
NSDictionary *headers = @{@"Host": @"dns.google.com"};
|
||||
|
||||
NSMutableArray *signals = [[NSMutableArray alloc] init];
|
||||
for (NSString *host in hosts) {
|
||||
MTSignal *signal = [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/resolve?name=%@&type=16", host, isTesting ? @"tapv2.stel.com" : @"apv2.stel.com"]] headers:headers] mapToSignal:^MTSignal *(NSData *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(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];
|
||||
}
|
||||
|
||||
+ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext {
|
||||
MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy];
|
||||
|
||||
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 apiEnvironment:apiEnvironment isTestingEnvironment:currentContext.isTestingEnvironment useTempAuthKeys:address.datacenterId != 0 ? currentContext.useTempAuthKeys : false];
|
||||
|
||||
if (address.datacenterId != 0) {
|
||||
//context.keychain = currentContext.keychain;
|
||||
}
|
||||
|
||||
MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:address.datacenterId usageCalculationInfo:nil];
|
||||
if (address.datacenterId != 0) {
|
||||
mtProto.useTempAuthKeys = currentContext.useTempAuthKeys;
|
||||
}
|
||||
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 NSTimeInterval completionTimestamp, 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 {
|
||||
NSMutableArray *signals = [[NSMutableArray alloc] init];
|
||||
[signals addObject:[self fetchBackupIpsResolveGoogle:isTestingEnvironment phoneNumber:phoneNumber currentContext:currentContext]];
|
||||
if (additionalSource != nil) {
|
||||
[signals addObject:additionalSource];
|
||||
}
|
||||
|
||||
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];
|
||||
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
|
11
submodules/MtProtoKit/MTBag.h
Normal file
11
submodules/MtProtoKit/MTBag.h
Normal file
@ -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
|
74
submodules/MtProtoKit/MTBag.m
Normal file
74
submodules/MtProtoKit/MTBag.m
Normal file
@ -0,0 +1,74 @@
|
||||
#import "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
|
11
submodules/MtProtoKit/MTBindingTempAuthKeyContext.h
Normal file
11
submodules/MtProtoKit/MTBindingTempAuthKeyContext.h
Normal file
@ -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
|
17
submodules/MtProtoKit/MTBindingTempAuthKeyContext.m
Normal file
17
submodules/MtProtoKit/MTBindingTempAuthKeyContext.m
Normal file
@ -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
|
11
submodules/MtProtoKit/MTConnectionProbing.h
Normal file
11
submodules/MtProtoKit/MTConnectionProbing.h
Normal file
@ -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
|
177
submodules/MtProtoKit/MTConnectionProbing.m
Normal file
177
submodules/MtProtoKit/MTConnectionProbing.m
Normal file
@ -0,0 +1,177 @@
|
||||
#import "MTConnectionProbing.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
# import <MTProtoKitDynamic/MTQueue.h>
|
||||
# import <MTProtoKitDynamic/MTAtomic.h>
|
||||
# import <MTProtoKitDynamic/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitDynamic/MTEncryption.h>
|
||||
# import <MTProtoKitDynamic/MTRequestMessageService.h>
|
||||
# import <MTProtoKitDynamic/MTRequest.h>
|
||||
# import <MTProtoKitDynamic/MTContext.h>
|
||||
# import <MTProtoKitDynamic/MTApiEnvironment.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitDynamic/MTProto.h>
|
||||
# import <MTProtoKitDynamic/MTSerialization.h>
|
||||
# import <MTProtoKitDynamic/MTLogging.h>
|
||||
# import <MTProtoKitDynamic/MTProxyConnectivity.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
# import <MTProtoKitMac/MTQueue.h>
|
||||
# import <MTProtoKitMac/MTAtomic.h>
|
||||
# import <MTProtoKitMac/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitMac/MTEncryption.h>
|
||||
# import <MTProtoKitMac/MTRequestMessageService.h>
|
||||
# import <MTProtoKitMac/MTRequest.h>
|
||||
# import <MTProtoKitMac/MTContext.h>
|
||||
# import <MTProtoKitMac/MTApiEnvironment.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitMac/MTProto.h>
|
||||
# import <MTProtoKitMac/MTSerialization.h>
|
||||
# import <MTProtoKitMac/MTLogging.h>
|
||||
# import <MTProtoKitMac/MTProxyConnectivity.h>
|
||||
#else
|
||||
# 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>
|
||||
#endif
|
||||
|
||||
#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
|
11
submodules/MtProtoKit/MTDNS.h
Normal file
11
submodules/MtProtoKit/MTDNS.h
Normal 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
|
372
submodules/MtProtoKit/MTDNS.m
Normal file
372
submodules/MtProtoKit/MTDNS.m
Normal file
@ -0,0 +1,372 @@
|
||||
#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>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTQueue.h>
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
# import <MTProtoKitDynamic/MTBag.h>
|
||||
# import <MTProtoKitDynamic/MTAtomic.h>
|
||||
# import <MTProtoKitDynamic/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitDynamic/MTEncryption.h>
|
||||
# import <MTProtoKitDynamic/MTRequestMessageService.h>
|
||||
# import <MTProtoKitDynamic/MTRequest.h>
|
||||
# import <MTProtoKitDynamic/MTContext.h>
|
||||
# import <MTProtoKitDynamic/MTApiEnvironment.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitDynamic/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitDynamic/MTProto.h>
|
||||
# import <MTProtoKitDynamic/MTSerialization.h>
|
||||
# import <MTProtoKitDynamic/MTLogging.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTQueue.h>
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
# import <MTProtoKitMac/MTBag.h>
|
||||
# import <MTProtoKitMac/MTAtomic.h>
|
||||
# import <MTProtoKitMac/MTHttpRequestOperation.h>
|
||||
# import <MTProtoKitMac/MTEncryption.h>
|
||||
# import <MTProtoKitMac/MTRequestMessageService.h>
|
||||
# import <MTProtoKitMac/MTRequest.h>
|
||||
# import <MTProtoKitMac/MTContext.h>
|
||||
# import <MTProtoKitMac/MTApiEnvironment.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddress.h>
|
||||
# import <MTProtoKitMac/MTDatacenterAddressSet.h>
|
||||
# import <MTProtoKitMac/MTProto.h>
|
||||
# import <MTProtoKitMac/MTSerialization.h>
|
||||
# import <MTProtoKitMac/MTLogging.h>
|
||||
#else
|
||||
# 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>
|
||||
#endif
|
||||
|
||||
#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]] startWithNext:^(NSString *result) {
|
||||
__strong MTDNSContext *strongSelf = weakSelf;
|
||||
if (strongSelf == nil) {
|
||||
return;
|
||||
}
|
||||
if (strongSelf->_contexts[key] != nil) {
|
||||
[strongSelf->_contexts[key] complete:result];
|
||||
[strongSelf->_contexts removeObjectForKey:key];
|
||||
}
|
||||
}]];
|
||||
}
|
||||
|
||||
__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 *(NSData *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
|
10
submodules/MtProtoKit/MTDatacenterVerificationData.h
Normal file
10
submodules/MtProtoKit/MTDatacenterVerificationData.h
Normal file
@ -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
|
18
submodules/MtProtoKit/MTDatacenterVerificationData.m
Normal file
18
submodules/MtProtoKit/MTDatacenterVerificationData.m
Normal file
@ -0,0 +1,18 @@
|
||||
#import "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
|
17
submodules/MtProtoKit/MTDiscoverConnectionSignals.h
Normal file
17
submodules/MtProtoKit/MTDiscoverConnectionSignals.h
Normal file
@ -0,0 +1,17 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class MTContext;
|
||||
@class MTDatacenterAddress;
|
||||
@class MTSignal;
|
||||
|
||||
typedef struct {
|
||||
uint8_t nonce[16];
|
||||
} MTPayloadData;
|
||||
|
||||
@interface MTDiscoverConnectionSignals : NSObject
|
||||
|
||||
+ (NSData *)payloadData:(MTPayloadData *)outPayloadData context:(MTContext *)context address:(MTDatacenterAddress *)address;
|
||||
|
||||
+ (MTSignal *)discoverSchemeWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId addressList:(NSArray *)addressList media:(bool)media isProxy:(bool)isProxy;
|
||||
|
||||
@end
|
268
submodules/MtProtoKit/MTDiscoverConnectionSignals.m
Normal file
268
submodules/MtProtoKit/MTDiscoverConnectionSignals.m
Normal file
@ -0,0 +1,268 @@
|
||||
#import "MTDiscoverConnectionSignals.h"
|
||||
|
||||
#import "MTTcpConnection.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTTransportScheme.h>
|
||||
# import <MTProtoKitDynamic/MTTcpTransport.h>
|
||||
# import <MTProtoKitDynamic/MTQueue.h>
|
||||
# import <MTProtoKitDynamic/MTProtoKitDynamic.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTTransportScheme.h>
|
||||
# import <MTProtoKitMac/MTTcpTransport.h>
|
||||
# import <MTProtoKitMac/MTQueue.h>
|
||||
# import <MTProtoKitMac/MTProtoKitMac.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTTransportScheme.h>
|
||||
# import <MtProtoKit/MTTcpTransport.h>
|
||||
# import <MtProtoKit/MTQueue.h>
|
||||
# import <MtProtoKit/MTProtoKit.h>
|
||||
#endif
|
||||
|
||||
#import "MTDatacenterAddress.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTDisposable.h>
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
# import <MTProtoKitDynamic/MTAtomic.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTDisposable.h>
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
# import <MTProtoKitMac/MTAtomic.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTDisposable.h>
|
||||
# import <MtProtoKit/MTSignal.h>
|
||||
# import <MtProtoKit/MTAtomic.h>
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
if ([MTSocksProxySettings secretSupportsExtendedPadding:secret]) {
|
||||
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];
|
||||
__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];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
26
submodules/MtProtoKit/MTDisposable.h
Normal file
26
submodules/MtProtoKit/MTDisposable.h
Normal file
@ -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
|
198
submodules/MtProtoKit/MTDisposable.m
Normal file
198
submodules/MtProtoKit/MTDisposable.m
Normal file
@ -0,0 +1,198 @@
|
||||
#import "MTDisposable.h"
|
||||
|
||||
#import <libkern/OSAtomic.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface MTBlockDisposable ()
|
||||
{
|
||||
void *_block;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTBlockDisposable
|
||||
|
||||
- (instancetype)initWithBlock:(void (^)())block
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_block = (__bridge_retained void *)[block copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
void *block = _block;
|
||||
if (block != NULL)
|
||||
{
|
||||
if (OSAtomicCompareAndSwapPtr(block, 0, &_block))
|
||||
{
|
||||
if (block != nil)
|
||||
{
|
||||
__strong id strongBlock = (__bridge_transfer id)block;
|
||||
strongBlock = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dispose
|
||||
{
|
||||
void *block = _block;
|
||||
if (block != NULL)
|
||||
{
|
||||
if (OSAtomicCompareAndSwapPtr(block, 0, &_block))
|
||||
{
|
||||
if (block != nil)
|
||||
{
|
||||
__strong id strongBlock = (__bridge_transfer id)block;
|
||||
((dispatch_block_t)strongBlock)();
|
||||
strongBlock = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface MTMetaDisposable ()
|
||||
{
|
||||
OSSpinLock _lock;
|
||||
bool _disposed;
|
||||
id<MTDisposable> _disposable;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTMetaDisposable
|
||||
|
||||
- (void)setDisposable:(id<MTDisposable>)disposable
|
||||
{
|
||||
id<MTDisposable> previousDisposable = nil;
|
||||
bool dispose = false;
|
||||
|
||||
OSSpinLockLock(&_lock);
|
||||
dispose = _disposed;
|
||||
if (!dispose)
|
||||
{
|
||||
previousDisposable = _disposable;
|
||||
_disposable = disposable;
|
||||
}
|
||||
OSSpinLockUnlock(&_lock);
|
||||
|
||||
if (previousDisposable != nil)
|
||||
[previousDisposable dispose];
|
||||
|
||||
if (dispose)
|
||||
[disposable dispose];
|
||||
}
|
||||
|
||||
- (void)dispose
|
||||
{
|
||||
id<MTDisposable> disposable = nil;
|
||||
|
||||
OSSpinLockLock(&_lock);
|
||||
if (!_disposed)
|
||||
{
|
||||
disposable = _disposable;
|
||||
_disposed = true;
|
||||
}
|
||||
OSSpinLockUnlock(&_lock);
|
||||
|
||||
if (disposable != nil)
|
||||
[disposable dispose];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface MTDisposableSet ()
|
||||
{
|
||||
OSSpinLock _lock;
|
||||
bool _disposed;
|
||||
id<MTDisposable> _singleDisposable;
|
||||
NSArray *_multipleDisposables;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDisposableSet
|
||||
|
||||
- (void)add:(id<MTDisposable>)disposable
|
||||
{
|
||||
if (disposable == nil)
|
||||
return;
|
||||
|
||||
bool dispose = false;
|
||||
|
||||
OSSpinLockLock(&_lock);
|
||||
dispose = _disposed;
|
||||
if (!dispose)
|
||||
{
|
||||
if (_multipleDisposables != nil)
|
||||
{
|
||||
NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables];
|
||||
[multipleDisposables addObject:disposable];
|
||||
_multipleDisposables = multipleDisposables;
|
||||
}
|
||||
else if (_singleDisposable != nil)
|
||||
{
|
||||
NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithObjects:_singleDisposable, disposable, nil];
|
||||
_multipleDisposables = multipleDisposables;
|
||||
_singleDisposable = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
_singleDisposable = disposable;
|
||||
}
|
||||
}
|
||||
OSSpinLockUnlock(&_lock);
|
||||
|
||||
if (dispose)
|
||||
[disposable dispose];
|
||||
}
|
||||
|
||||
- (void)remove:(id<MTDisposable>)disposable {
|
||||
OSSpinLockLock(&_lock);
|
||||
if (_multipleDisposables != nil)
|
||||
{
|
||||
NSMutableArray *multipleDisposables = [[NSMutableArray alloc] initWithArray:_multipleDisposables];
|
||||
[multipleDisposables removeObject:disposable];
|
||||
_multipleDisposables = multipleDisposables;
|
||||
}
|
||||
else if (_singleDisposable == disposable)
|
||||
{
|
||||
_singleDisposable = nil;
|
||||
}
|
||||
OSSpinLockUnlock(&_lock);
|
||||
}
|
||||
|
||||
- (void)dispose
|
||||
{
|
||||
id<MTDisposable> singleDisposable = nil;
|
||||
NSArray *multipleDisposables = nil;
|
||||
|
||||
OSSpinLockLock(&_lock);
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
singleDisposable = _singleDisposable;
|
||||
multipleDisposables = _multipleDisposables;
|
||||
_singleDisposable = nil;
|
||||
_multipleDisposables = nil;
|
||||
}
|
||||
OSSpinLockUnlock(&_lock);
|
||||
|
||||
if (singleDisposable != nil)
|
||||
[singleDisposable dispose];
|
||||
if (multipleDisposables != nil)
|
||||
{
|
||||
for (id<MTDisposable> disposable in multipleDisposables)
|
||||
{
|
||||
[disposable dispose];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
11
submodules/MtProtoKit/MTGzip.h
Normal file
11
submodules/MtProtoKit/MTGzip.h
Normal file
@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MTGzip : NSObject
|
||||
|
||||
+ (NSData * _Nullable)decompress:(NSData *)data;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
53
submodules/MtProtoKit/MTGzip.m
Normal file
53
submodules/MtProtoKit/MTGzip.m
Normal file
@ -0,0 +1,53 @@
|
||||
#import "MTGzip.h"
|
||||
|
||||
#import <zlib.h>
|
||||
|
||||
@implementation MTGzip
|
||||
|
||||
+ (NSData * _Nullable)decompress:(NSData *)data {
|
||||
const int kMemoryChunkSize = 1024;
|
||||
|
||||
NSUInteger length = [data length];
|
||||
int windowBits = 15 + 32; //Default + gzip header instead of zlib header
|
||||
int retCode;
|
||||
unsigned char output[kMemoryChunkSize];
|
||||
uInt gotBack;
|
||||
NSMutableData *result;
|
||||
z_stream stream;
|
||||
|
||||
if ((length == 0) || (length > UINT_MAX)) //FIXME: Support 64 bit inputs
|
||||
return nil;
|
||||
|
||||
bzero(&stream, sizeof(z_stream));
|
||||
stream.avail_in = (uInt)length;
|
||||
stream.next_in = (unsigned char*)[data bytes];
|
||||
|
||||
retCode = inflateInit2(&stream, windowBits);
|
||||
if(retCode != Z_OK)
|
||||
{
|
||||
NSLog(@"%s: inflateInit2() failed with error %i", __PRETTY_FUNCTION__, retCode);
|
||||
return nil;
|
||||
}
|
||||
|
||||
result = [NSMutableData dataWithCapacity:(length * 4)];
|
||||
do
|
||||
{
|
||||
stream.avail_out = kMemoryChunkSize;
|
||||
stream.next_out = output;
|
||||
retCode = inflate(&stream, Z_NO_FLUSH);
|
||||
if ((retCode != Z_OK) && (retCode != Z_STREAM_END))
|
||||
{
|
||||
NSLog(@"%s: inflate() failed with error %i", __PRETTY_FUNCTION__, retCode);
|
||||
inflateEnd(&stream);
|
||||
return nil;
|
||||
}
|
||||
gotBack = kMemoryChunkSize - stream.avail_out;
|
||||
if (gotBack > 0)
|
||||
[result appendBytes:output length:gotBack];
|
||||
} while( retCode == Z_OK);
|
||||
inflateEnd(&stream);
|
||||
|
||||
return (retCode == Z_STREAM_END ? result : nil);
|
||||
}
|
||||
|
||||
@end
|
15
submodules/MtProtoKit/MTNetworkUsageCalculationInfo.h
Normal file
15
submodules/MtProtoKit/MTNetworkUsageCalculationInfo.h
Normal file
@ -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
|
17
submodules/MtProtoKit/MTNetworkUsageCalculationInfo.m
Normal file
17
submodules/MtProtoKit/MTNetworkUsageCalculationInfo.m
Normal file
@ -0,0 +1,17 @@
|
||||
#import "MTNetworkUsageCalculationInfo.h"
|
||||
|
||||
@implementation MTNetworkUsageCalculationInfo
|
||||
|
||||
- (instancetype)initWithFilePath:(NSString *)filePath incomingWWANKey:(int32_t)incomingWWANKey outgoingWWANKey:(int32_t)outgoingWWANKey incomingOtherKey:(int32_t)incomingOtherKey outgoingOtherKey:(int32_t)outgoingOtherKey {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_filePath = filePath;
|
||||
_incomingWWANKey = incomingWWANKey;
|
||||
_outgoingWWANKey = outgoingWWANKey;
|
||||
_incomingOtherKey = incomingOtherKey;
|
||||
_outgoingOtherKey = outgoingOtherKey;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
26
submodules/MtProtoKit/MTNetworkUsageManager.h
Normal file
26
submodules/MtProtoKit/MTNetworkUsageManager.h
Normal file
@ -0,0 +1,26 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class MTSignal;
|
||||
@class MTNetworkUsageCalculationInfo;
|
||||
|
||||
typedef enum {
|
||||
MTNetworkUsageManagerInterfaceWWAN,
|
||||
MTNetworkUsageManagerInterfaceOther
|
||||
} MTNetworkUsageManagerInterface;
|
||||
|
||||
typedef struct {
|
||||
NSUInteger incomingBytes;
|
||||
NSUInteger outgoingBytes;
|
||||
} MTNetworkUsageManagerInterfaceStats;
|
||||
|
||||
@interface MTNetworkUsageManager : NSObject
|
||||
|
||||
- (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
|
259
submodules/MtProtoKit/MTNetworkUsageManager.m
Normal file
259
submodules/MtProtoKit/MTNetworkUsageManager.m
Normal file
@ -0,0 +1,259 @@
|
||||
#import "MTNetworkUsageManager.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTNetworkUsageCalculationInfo.h>
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
# import <MTProtoKitDynamic/MTTimer.h>
|
||||
# import <MTProtoKitDynamic/MTQueue.h>
|
||||
# import <MTProtoKitDynamic/MTAtomic.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTNetworkUsageCalculationInfo.h>
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
# import <MTProtoKitMac/MTTimer.h>
|
||||
# import <MTProtoKitMac/MTQueue.h>
|
||||
# import <MTProtoKitMac/MTAtomic.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTNetworkUsageCalculationInfo.h>
|
||||
# import <MtProtoKit/MTSignal.h>
|
||||
# import <MtProtoKit/MTTimer.h>
|
||||
# import <MtProtoKit/MTQueue.h>
|
||||
# import <MtProtoKit/MTAtomic.h>
|
||||
#endif
|
||||
|
||||
static int offsetForInterface(MTNetworkUsageCalculationInfo *info, MTNetworkUsageManagerInterface interface, bool incoming) {
|
||||
switch (interface) {
|
||||
case MTNetworkUsageManagerInterfaceWWAN:
|
||||
if (incoming) {
|
||||
return info.incomingWWANKey * 8;
|
||||
} else {
|
||||
return info.outgoingWWANKey * 8;
|
||||
}
|
||||
case MTNetworkUsageManagerInterfaceOther:
|
||||
if (incoming) {
|
||||
return info.incomingOtherKey * 8;
|
||||
} else {
|
||||
return info.outgoingOtherKey * 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@interface MTNetworkUsageManagerImpl : NSObject {
|
||||
MTQueue *_queue;
|
||||
MTNetworkUsageCalculationInfo *_info;
|
||||
|
||||
NSMutableDictionary<NSNumber *, NSNumber *> *_pendingIncomingBytes;
|
||||
NSMutableDictionary<NSNumber *, NSNumber *> *_pendingOutgoingBytes;
|
||||
MTTimer *_timer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTNetworkUsageManagerImpl
|
||||
|
||||
- (instancetype)initWithQueue:(MTQueue *)queue info:(MTNetworkUsageCalculationInfo *)info {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_queue = queue;
|
||||
_info = info;
|
||||
|
||||
_pendingIncomingBytes = [[NSMutableDictionary alloc] init];
|
||||
_pendingOutgoingBytes = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self sync];
|
||||
}
|
||||
|
||||
- (void)scheduleSync {
|
||||
if (_timer == nil) {
|
||||
__weak MTNetworkUsageManagerImpl *weakSelf = self;
|
||||
_timer = [[MTTimer alloc] initWithTimeout:1.0 repeat:false completion:^{
|
||||
__strong MTNetworkUsageManagerImpl *strongSelf = weakSelf;
|
||||
[strongSelf sync];
|
||||
} queue:_queue.nativeQueue];
|
||||
[_timer start];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sync {
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
|
||||
int32_t fd = open([_info.filePath UTF8String], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fd >= 0) {
|
||||
[_pendingIncomingBytes enumerateKeysAndObjectsUsingBlock:^(NSNumber * nInterface, NSNumber *nValue, __unused BOOL *stop) {
|
||||
off_t offset = offsetForInterface(_info, (MTNetworkUsageManagerInterface)[nInterface intValue], true);
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
int64_t currentValue = 0;
|
||||
read(fd, ¤tValue, 8);
|
||||
currentValue += (int64_t)[nValue intValue];
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
write(fd, ¤tValue, 8);
|
||||
}];
|
||||
[_pendingOutgoingBytes enumerateKeysAndObjectsUsingBlock:^(NSNumber * nInterface, NSNumber *nValue, __unused BOOL *stop) {
|
||||
off_t offset = offsetForInterface(_info, (MTNetworkUsageManagerInterface)[nInterface intValue], false);
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
int64_t currentValue = 0;
|
||||
read(fd, ¤tValue, 8);
|
||||
currentValue += (int64_t)[nValue intValue];
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
write(fd, ¤tValue, 8);
|
||||
}];
|
||||
close(fd);
|
||||
}
|
||||
|
||||
[_pendingIncomingBytes removeAllObjects];
|
||||
[_pendingOutgoingBytes removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)addIncomingBytes:(NSUInteger)incomingBytes interface:(MTNetworkUsageManagerInterface)interface {
|
||||
_pendingIncomingBytes[@(interface)] = @([_pendingIncomingBytes[@(interface)] unsignedIntegerValue] + incomingBytes);
|
||||
[self scheduleSync];
|
||||
}
|
||||
|
||||
- (void)addOutgoingBytes:(NSUInteger)outgoingBytes interface:(MTNetworkUsageManagerInterface)interface {
|
||||
_pendingOutgoingBytes[@(interface)] = @([_pendingOutgoingBytes[@(interface)] unsignedIntegerValue] + outgoingBytes);
|
||||
[self scheduleSync];
|
||||
}
|
||||
|
||||
- (void)resetKeys:(NSArray<NSNumber *> *)keys setKeys:(NSDictionary<NSNumber *, NSNumber *> *)setKeys completion:(void (^)())completion {
|
||||
[self sync];
|
||||
int32_t fd = open([_info.filePath UTF8String], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fd >= 0) {
|
||||
for (NSNumber *nKey in keys) {
|
||||
lseek(fd, [nKey intValue] * 8, SEEK_SET);
|
||||
int64_t currentValue = 0;
|
||||
write(fd, ¤tValue, 8);
|
||||
}
|
||||
[setKeys enumerateKeysAndObjectsUsingBlock:^(NSNumber *nKey, NSNumber *nValue, __unused BOOL *stop) {
|
||||
lseek(fd, [nKey intValue] * 8, SEEK_SET);
|
||||
int64_t currentValue = [nValue longLongValue];
|
||||
write(fd, ¤tValue, 8);
|
||||
}];
|
||||
close(fd);
|
||||
}
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)currentStatsForKeys:(NSArray<NSNumber *> *)keys {
|
||||
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
|
||||
[self sync];
|
||||
int32_t fd = open([_info.filePath UTF8String], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fd >= 0) {
|
||||
for (NSNumber *nKey in keys) {
|
||||
lseek(fd, [nKey intValue] * 8, SEEK_SET);
|
||||
int64_t currentValue = 0;
|
||||
read(fd, ¤tValue, 8);
|
||||
result[nKey] = @(currentValue);
|
||||
}
|
||||
int64_t currentValue = 0;
|
||||
read(fd, ¤tValue, 8);
|
||||
close(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface MTNetworkUsageManagerImplHolder: NSObject
|
||||
|
||||
@property (nonatomic) void *impl;
|
||||
@property (nonatomic) bool deallocated;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTNetworkUsageManagerImplHolder
|
||||
|
||||
@end
|
||||
|
||||
@interface MTNetworkUsageManager () {
|
||||
MTQueue *_queue;
|
||||
MTAtomic *_holder;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTNetworkUsageManager
|
||||
|
||||
- (instancetype)initWithInfo:(MTNetworkUsageCalculationInfo *)info {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_queue = [[MTQueue alloc] init];
|
||||
_holder = [[MTAtomic alloc] initWithValue:[[MTNetworkUsageManagerImplHolder alloc] init]];
|
||||
[_queue dispatchOnQueue:^{
|
||||
[_holder with:^id (MTNetworkUsageManagerImplHolder *holder) {
|
||||
if (!holder.deallocated) {
|
||||
holder.impl = (void *)CFBridgingRetain([[MTNetworkUsageManagerImpl alloc] initWithQueue:_queue info:info]);
|
||||
}
|
||||
return nil;
|
||||
}];
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
MTAtomic *holder = _holder;
|
||||
[holder with:^id (MTNetworkUsageManagerImplHolder *holder) {
|
||||
holder.deallocated = true;
|
||||
return nil;
|
||||
}];
|
||||
[_queue dispatchOnQueue:^{
|
||||
__block void *impl = nil;
|
||||
[holder with:^id (MTNetworkUsageManagerImplHolder *holder) {
|
||||
impl = holder.impl;
|
||||
holder.impl = nil;
|
||||
return nil;
|
||||
}];
|
||||
CFBridgingRelease(impl);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)with:(void (^)(MTNetworkUsageManagerImpl *))f {
|
||||
[_queue dispatchOnQueue:^{
|
||||
__block __strong MTNetworkUsageManagerImpl *impl = nil;
|
||||
[_holder with:^id (MTNetworkUsageManagerImplHolder *holder) {
|
||||
impl = (__bridge MTNetworkUsageManagerImpl *)holder.impl;
|
||||
return nil;
|
||||
}];
|
||||
f(impl);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addIncomingBytes:(NSUInteger)incomingBytes interface:(MTNetworkUsageManagerInterface)interface {
|
||||
[self with:^(MTNetworkUsageManagerImpl *impl) {
|
||||
[impl addIncomingBytes:incomingBytes interface:interface];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)addOutgoingBytes:(NSUInteger)outgoingBytes interface:(MTNetworkUsageManagerInterface)interface {
|
||||
[self with:^(MTNetworkUsageManagerImpl *impl) {
|
||||
[impl addOutgoingBytes:outgoingBytes interface:interface];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)resetKeys:(NSArray<NSNumber *> *)keys setKeys:(NSDictionary<NSNumber *, NSNumber *> *)setKeys completion:(void (^)())completion {
|
||||
[self with:^(MTNetworkUsageManagerImpl *impl) {
|
||||
[impl resetKeys:keys setKeys:setKeys completion:completion];
|
||||
}];
|
||||
}
|
||||
|
||||
- (MTSignal *)currentStatsForKeys:(NSArray<NSNumber *> *)keys {
|
||||
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
|
||||
[self with:^(MTNetworkUsageManagerImpl *impl) {
|
||||
NSDictionary *result = [impl currentStatsForKeys:keys];
|
||||
[subscriber putNext:result];
|
||||
[subscriber putCompletion];
|
||||
}];
|
||||
return nil;
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
14
submodules/MtProtoKit/MTPKCS.h
Normal file
14
submodules/MtProtoKit/MTPKCS.h
Normal file
@ -0,0 +1,14 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MTPKCS : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *name;
|
||||
@property (nonatomic, strong, readonly) NSData *data;
|
||||
|
||||
+ (MTPKCS * _Nullable)parse:(const unsigned char *)buffer size:(int)size;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
59
submodules/MtProtoKit/MTPKCS.m
Normal file
59
submodules/MtProtoKit/MTPKCS.m
Normal file
@ -0,0 +1,59 @@
|
||||
#import "MTPKCS.h"
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
|
||||
@implementation MTPKCS
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name data:(NSData *)data {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_name = name;
|
||||
_data = data;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (MTPKCS * _Nullable)parse:(const unsigned char *)buffer size:(int)size {
|
||||
MTPKCS * _Nullable result = nil;
|
||||
PKCS7 *pkcs7 = NULL;
|
||||
STACK_OF(X509) *signers = NULL;
|
||||
|
||||
pkcs7 = d2i_PKCS7(NULL, &buffer, size);
|
||||
if (pkcs7 == NULL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!PKCS7_type_is_signed(pkcs7)) {
|
||||
if (pkcs7) {
|
||||
PKCS7_free(pkcs7);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
signers = PKCS7_get0_signers(pkcs7, NULL, PKCS7_BINARY);
|
||||
if (signers == NULL) {
|
||||
if (pkcs7) {
|
||||
PKCS7_free(pkcs7);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
const X509* cert = sk_X509_pop(signers);
|
||||
if (cert == NULL) {
|
||||
if (signers) {
|
||||
sk_X509_free(signers);
|
||||
}
|
||||
if (pkcs7) {
|
||||
PKCS7_free(pkcs7);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
result = [[MTPKCS alloc] initWithName:[NSString stringWithUTF8String:cert->name] data:[NSData dataWithBytes:cert->cert_info->key->public_key->data length:cert->cert_info->key->public_key->length]];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
26
submodules/MtProtoKit/MTProtoKit/Info.plist
Normal file
26
submodules/MtProtoKit/MTProtoKit/Info.plist
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
56
submodules/MtProtoKit/MTProtoKit/MTApiEnvironment.h
Normal file
56
submodules/MtProtoKit/MTProtoKit/MTApiEnvironment.h
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTSocksProxySettings : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *ip;
|
||||
@property (nonatomic, readonly) uint16_t port;
|
||||
@property (nonatomic, strong, readonly) NSString *username;
|
||||
@property (nonatomic, strong, readonly) NSString *password;
|
||||
@property (nonatomic, strong, readonly) NSData *secret;
|
||||
|
||||
- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password secret:(NSData *)secret;
|
||||
|
||||
+ (bool)secretSupportsExtendedPadding:(NSData *)data;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTNetworkSettings : NSObject
|
||||
|
||||
@property (nonatomic, readonly) bool reducedBackupDiscoveryTimeout;
|
||||
|
||||
- (instancetype)initWithReducedBackupDiscoveryTimeout:(bool)reducedBackupDiscoveryTimeout;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTApiEnvironment : NSObject
|
||||
|
||||
@property (nonatomic) int32_t apiId;
|
||||
@property (nonatomic, strong, readonly) NSString *deviceModel;
|
||||
@property (nonatomic, strong, readonly) NSString *systemVersion;
|
||||
@property (nonatomic, strong) NSString *appVersion;
|
||||
@property (nonatomic, strong, readonly) NSString *systemLangCode;
|
||||
@property (nonatomic, strong) NSNumber *layer;
|
||||
@property (nonatomic, strong, readonly) NSData *systemCode;
|
||||
|
||||
@property (nonatomic, strong) NSString *langPack;
|
||||
@property (nonatomic, strong, readonly) NSString *langPackCode;
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *apiInitializationHash;
|
||||
|
||||
@property (nonatomic) bool disableUpdates;
|
||||
@property (nonatomic) NSData *tcpPayloadPrefix;
|
||||
@property (nonatomic) NSDictionary *datacenterAddressOverrides;
|
||||
|
||||
@property (nonatomic, strong, readonly) MTSocksProxySettings *socksProxySettings;
|
||||
@property (nonatomic, strong, readonly) MTNetworkSettings *networkSettings;
|
||||
|
||||
@property (nonatomic, copy) void (^passwordInputHandler)(void);
|
||||
|
||||
- (MTApiEnvironment *)withUpdatedLangPackCode:(NSString *)langPackCode;
|
||||
- (MTApiEnvironment *)withUpdatedSocksProxySettings:(MTSocksProxySettings *)socksProxySettings;
|
||||
- (MTApiEnvironment *)withUpdatedNetworkSettings:(MTNetworkSettings *)networkSettings;
|
||||
- (MTApiEnvironment *)withUpdatedSystemCode:(NSData *)systemCode;
|
||||
|
||||
@end
|
625
submodules/MtProtoKit/MTProtoKit/MTApiEnvironment.m
Normal file
625
submodules/MtProtoKit/MTProtoKit/MTApiEnvironment.m
Normal file
@ -0,0 +1,625 @@
|
||||
|
||||
|
||||
#import "MTApiEnvironment.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
# import <UIKit/UIKit.h>
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
#define IFPGA_NAMESTRING @"iFPGA"
|
||||
|
||||
#define IPHONE_1G_NAMESTRING @"iPhone 1G"
|
||||
#define IPHONE_3G_NAMESTRING @"iPhone 3G"
|
||||
#define IPHONE_3GS_NAMESTRING @"iPhone 3GS"
|
||||
#define IPHONE_4_NAMESTRING @"iPhone 4"
|
||||
#define IPHONE_4S_NAMESTRING @"iPhone 4S"
|
||||
#define IPHONE_5_NAMESTRING @"iPhone 5"
|
||||
#define IPHONE_5S_NAMESTRING @"iPhone 5S"
|
||||
#define IPHONE_6_NAMESTRING @"iPhone 6"
|
||||
#define IPHONE_6Plus_NAMESTRING @"iPhone 6 Plus"
|
||||
#define IPHONE_6S_NAMESTRING @"iPhone 6S"
|
||||
#define IPHONE_6SPlus_NAMESTRING @"iPhone 6S Plus"
|
||||
#define IPHONE_7_NAMESTRING @"iPhone 7"
|
||||
#define IPHONE_7Plus_NAMESTRING @"iPhone 7 Plus"
|
||||
#define IPHONE_8_NAMESTRING @"iPhone 8"
|
||||
#define IPHONE_8Plus_NAMESTRING @"iPhone 8 Plus"
|
||||
#define IPHONE_X_NAMESTRING @"iPhone X"
|
||||
#define IPHONE_SE_NAMESTRING @"iPhone SE"
|
||||
#define IPHONE_UNKNOWN_NAMESTRING @"Unknown iPhone"
|
||||
#define IPHONE_XS_NAMESTRING @"iPhone XS"
|
||||
#define IPHONE_XSMAX_NAMESTRING @"iPhone XS Max"
|
||||
#define IPHONE_XR_NAMESTRING @"iPhone XR"
|
||||
|
||||
#define IPOD_1G_NAMESTRING @"iPod touch 1G"
|
||||
#define IPOD_2G_NAMESTRING @"iPod touch 2G"
|
||||
#define IPOD_3G_NAMESTRING @"iPod touch 3G"
|
||||
#define IPOD_4G_NAMESTRING @"iPod touch 4G"
|
||||
#define IPOD_5G_NAMESTRING @"iPod touch 5G"
|
||||
#define IPOD_6G_NAMESTRING @"iPod touch 6G"
|
||||
#define IPOD_UNKNOWN_NAMESTRING @"Unknown iPod"
|
||||
|
||||
#define IPAD_1G_NAMESTRING @"iPad 1G"
|
||||
#define IPAD_2G_NAMESTRING @"iPad 2G"
|
||||
#define IPAD_3G_NAMESTRING @"iPad 3G"
|
||||
#define IPAD_4G_NAMESTRING @"iPad 4G"
|
||||
#define IPAD_5G_NAMESTRING @"iPad Air 2"
|
||||
#define IPAD_6G_NAMESTRING @"iPad Pro"
|
||||
#define IPAD_PRO_3G_NAMESTRING @"iPad Pro 12.9 (3rd gen)"
|
||||
#define IPAD_PRO_11_NAMESTRING @"iPad Pro 11"
|
||||
#define IPAD_PRO_6G_NAMESTRING @"iPad (6th gen)"
|
||||
#define IPAD_PRO_10_5_NAMESTRING @"iPad Pro 10.5"
|
||||
#define IPAD_PRO_12_9_NAMESTRING @"iPad Pro 12.9"
|
||||
#define IPAD_UNKNOWN_NAMESTRING @"Unknown iPad"
|
||||
|
||||
#define APPLETV_2G_NAMESTRING @"Apple TV 2G"
|
||||
#define APPLETV_3G_NAMESTRING @"Apple TV 3G"
|
||||
#define APPLETV_4G_NAMESTRING @"Apple TV 4G"
|
||||
#define APPLETV_UNKNOWN_NAMESTRING @"Unknown Apple TV"
|
||||
|
||||
#define IOS_FAMILY_UNKNOWN_DEVICE @"Unknown iOS device"
|
||||
|
||||
#define SIMULATOR_NAMESTRING @"iPhone Simulator"
|
||||
#define SIMULATOR_IPHONE_NAMESTRING @"iPhone Simulator"
|
||||
#define SIMULATOR_IPAD_NAMESTRING @"iPad Simulator"
|
||||
#define SIMULATOR_APPLETV_NAMESTRING @"Apple TV Simulator" // :)
|
||||
|
||||
/*
|
||||
iPad8,5, iPad8,6, iPad8,7, iPad8,8 - iPad Pro 12.9" (3rd gen)
|
||||
iPad8,1, iPad8,2, iPad8,3, iPad8,4 - iPad Pro 11"
|
||||
iPad7,5, iPad7,6 - iPad 6th gen
|
||||
iPad7,3, iPad7,4 - iPad Pro 10.5"
|
||||
iPad7,1, iPad7,2 - iPad Pro 12.9" (2ng gen)
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
UIDeviceUnknown,
|
||||
|
||||
UIDeviceSimulator,
|
||||
UIDeviceSimulatoriPhone,
|
||||
UIDeviceSimulatoriPad,
|
||||
UIDeviceSimulatorAppleTV,
|
||||
|
||||
UIDevice1GiPhone,
|
||||
UIDevice3GiPhone,
|
||||
UIDevice3GSiPhone,
|
||||
UIDevice4iPhone,
|
||||
UIDevice4SiPhone,
|
||||
UIDevice5iPhone,
|
||||
UIDevice5SiPhone,
|
||||
UIDevice6iPhone,
|
||||
UIDevice6PlusiPhone,
|
||||
UIDevice6siPhone,
|
||||
UIDevice6SPlusiPhone,
|
||||
UIDevice7iPhone,
|
||||
UIDevice7PlusiPhone,
|
||||
UIDevice8iPhone,
|
||||
UIDevice8PlusiPhone,
|
||||
UIDeviceXiPhone,
|
||||
UIDeviceSEPhone,
|
||||
UIDeviceXSiPhone,
|
||||
UIDeviceXSMaxiPhone,
|
||||
UIDeviceXRiPhone,
|
||||
|
||||
UIDevice1GiPod,
|
||||
UIDevice2GiPod,
|
||||
UIDevice3GiPod,
|
||||
UIDevice4GiPod,
|
||||
UIDevice5GiPod,
|
||||
UIDevice6GiPod,
|
||||
|
||||
UIDevice1GiPad,
|
||||
UIDevice2GiPad,
|
||||
UIDevice3GiPad,
|
||||
UIDevice4GiPad,
|
||||
UIDevice5GiPad,
|
||||
UIDevice6GiPad,
|
||||
|
||||
UIDeviceiPadPro12_93g,
|
||||
UIDeviceiPadPro11,
|
||||
UIDeviceiPadPro6g,
|
||||
UIDeviceiPadPro10_5,
|
||||
UIDeviceiPadPro12_9,
|
||||
|
||||
UIDeviceAppleTV2,
|
||||
UIDeviceAppleTV3,
|
||||
UIDeviceAppleTV4,
|
||||
|
||||
UIDeviceUnknowniPhone,
|
||||
UIDeviceUnknowniPod,
|
||||
UIDeviceUnknowniPad,
|
||||
UIDeviceUnknownAppleTV,
|
||||
UIDeviceIFPGA,
|
||||
|
||||
UIDeviceOSX
|
||||
|
||||
} UIDevicePlatform;
|
||||
|
||||
typedef enum {
|
||||
UIDeviceFamilyiPhone,
|
||||
UIDeviceFamilyiPod,
|
||||
UIDeviceFamilyiPad,
|
||||
UIDeviceFamilyAppleTV,
|
||||
UIDeviceFamilyUnknown,
|
||||
|
||||
} UIDeviceFamily;
|
||||
|
||||
@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];
|
||||
}
|
||||
|
||||
+ (bool)secretSupportsExtendedPadding:(NSData *)data {
|
||||
if (data.length == 17) {
|
||||
uint8_t first = 0;
|
||||
[data getBytes:&first length:1];
|
||||
return (first == 0xdd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@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 = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_deviceModel = [self platformString];
|
||||
#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
|
||||
#ifdef BETA
|
||||
suffix = @" BETA";
|
||||
#endif
|
||||
|
||||
#ifdef APPSTORE
|
||||
suffix = @" APPSTORE";
|
||||
#endif
|
||||
|
||||
#ifdef STABLE
|
||||
suffix = @" STABLE";
|
||||
#endif
|
||||
#endif
|
||||
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
|
||||
{
|
||||
switch ([self platformType])
|
||||
{
|
||||
case UIDevice1GiPhone: return IPHONE_1G_NAMESTRING;
|
||||
case UIDevice3GiPhone: return IPHONE_3G_NAMESTRING;
|
||||
case UIDevice3GSiPhone: return IPHONE_3GS_NAMESTRING;
|
||||
case UIDevice4iPhone: return IPHONE_4_NAMESTRING;
|
||||
case UIDevice4SiPhone: return IPHONE_4S_NAMESTRING;
|
||||
case UIDevice5iPhone: return IPHONE_5_NAMESTRING;
|
||||
case UIDevice5SiPhone: return IPHONE_5S_NAMESTRING;
|
||||
case UIDevice6iPhone: return IPHONE_6_NAMESTRING;
|
||||
case UIDevice6PlusiPhone: return IPHONE_6Plus_NAMESTRING;
|
||||
case UIDevice6siPhone: return IPHONE_6S_NAMESTRING;
|
||||
case UIDevice6SPlusiPhone: return IPHONE_6SPlus_NAMESTRING;
|
||||
case UIDevice7iPhone: return IPHONE_7_NAMESTRING;
|
||||
case UIDevice7PlusiPhone: return IPHONE_7Plus_NAMESTRING;
|
||||
case UIDevice8iPhone: return IPHONE_8_NAMESTRING;
|
||||
case UIDevice8PlusiPhone: return IPHONE_8Plus_NAMESTRING;
|
||||
case UIDeviceXiPhone: return IPHONE_X_NAMESTRING;
|
||||
case UIDeviceSEPhone: return IPHONE_SE_NAMESTRING;
|
||||
case UIDeviceXSiPhone: return IPHONE_XS_NAMESTRING;
|
||||
case UIDeviceXSMaxiPhone: return IPHONE_XSMAX_NAMESTRING;
|
||||
case UIDeviceXRiPhone: return IPHONE_XR_NAMESTRING;
|
||||
|
||||
case UIDeviceUnknowniPhone: return IPHONE_UNKNOWN_NAMESTRING;
|
||||
|
||||
case UIDevice1GiPod: return IPOD_1G_NAMESTRING;
|
||||
case UIDevice2GiPod: return IPOD_2G_NAMESTRING;
|
||||
case UIDevice3GiPod: return IPOD_3G_NAMESTRING;
|
||||
case UIDevice4GiPod: return IPOD_4G_NAMESTRING;
|
||||
case UIDevice5GiPod: return IPOD_5G_NAMESTRING;
|
||||
case UIDevice6GiPod: return IPOD_6G_NAMESTRING;
|
||||
case UIDeviceUnknowniPod: return IPOD_UNKNOWN_NAMESTRING;
|
||||
|
||||
case UIDevice1GiPad : return IPAD_1G_NAMESTRING;
|
||||
case UIDevice2GiPad : return IPAD_2G_NAMESTRING;
|
||||
case UIDevice3GiPad : return IPAD_3G_NAMESTRING;
|
||||
case UIDevice4GiPad : return IPAD_4G_NAMESTRING;
|
||||
case UIDevice5GiPad : return IPAD_5G_NAMESTRING;
|
||||
case UIDevice6GiPad : return IPAD_6G_NAMESTRING;
|
||||
case UIDeviceiPadPro12_93g : return IPAD_PRO_12_9_NAMESTRING;
|
||||
case UIDeviceiPadPro11 : return IPAD_PRO_11_NAMESTRING;
|
||||
case UIDeviceiPadPro6g : return IPAD_PRO_6G_NAMESTRING;
|
||||
case UIDeviceiPadPro10_5 : return IPAD_PRO_10_5_NAMESTRING;
|
||||
case UIDeviceiPadPro12_9 : return IPAD_PRO_12_9_NAMESTRING;
|
||||
case UIDeviceUnknowniPad : return IPAD_UNKNOWN_NAMESTRING;
|
||||
|
||||
case UIDeviceAppleTV2 : return APPLETV_2G_NAMESTRING;
|
||||
case UIDeviceAppleTV3 : return APPLETV_3G_NAMESTRING;
|
||||
case UIDeviceAppleTV4 : return APPLETV_4G_NAMESTRING;
|
||||
case UIDeviceUnknownAppleTV: return APPLETV_UNKNOWN_NAMESTRING;
|
||||
|
||||
case UIDeviceSimulator: return SIMULATOR_NAMESTRING;
|
||||
case UIDeviceSimulatoriPhone: return SIMULATOR_IPHONE_NAMESTRING;
|
||||
case UIDeviceSimulatoriPad: return SIMULATOR_IPAD_NAMESTRING;
|
||||
case UIDeviceSimulatorAppleTV: return SIMULATOR_APPLETV_NAMESTRING;
|
||||
|
||||
case UIDeviceIFPGA: return IFPGA_NAMESTRING;
|
||||
|
||||
case UIDeviceOSX: return [self macHWName];
|
||||
|
||||
default: return IOS_FAMILY_UNKNOWN_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";
|
||||
}
|
||||
|
||||
- (NSUInteger)platformType
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
NSString *platform = [self platform];
|
||||
|
||||
// The ever mysterious iFPGA
|
||||
if ([platform isEqualToString:@"iFPGA"]) return UIDeviceIFPGA;
|
||||
|
||||
// iPhone
|
||||
if ([platform isEqualToString:@"iPhone1,1"]) return UIDevice1GiPhone;
|
||||
if ([platform isEqualToString:@"iPhone1,2"]) return UIDevice3GiPhone;
|
||||
if ([platform hasPrefix:@"iPhone2"]) return UIDevice3GSiPhone;
|
||||
if ([platform hasPrefix:@"iPhone3"]) return UIDevice4iPhone;
|
||||
if ([platform hasPrefix:@"iPhone4"]) return UIDevice4SiPhone;
|
||||
if ([platform hasPrefix:@"iPhone5"]) return UIDevice5iPhone;
|
||||
if ([platform hasPrefix:@"iPhone6"]) return UIDevice5SiPhone;
|
||||
|
||||
if ([platform isEqualToString:@"iPhone7,1"]) return UIDevice6PlusiPhone;
|
||||
if ([platform isEqualToString:@"iPhone7,2"]) return UIDevice6iPhone;
|
||||
if ([platform isEqualToString:@"iPhone8,1"]) return UIDevice6siPhone;
|
||||
if ([platform isEqualToString:@"iPhone8,2"]) return UIDevice6SPlusiPhone;
|
||||
if ([platform isEqualToString:@"iPhone9,1"]) return UIDevice7iPhone;
|
||||
if ([platform isEqualToString:@"iPhone9,3"]) return UIDevice7iPhone;
|
||||
if ([platform isEqualToString:@"iPhone9,2"]) return UIDevice7PlusiPhone;
|
||||
if ([platform isEqualToString:@"iPhone9,4"]) return UIDevice7PlusiPhone;
|
||||
|
||||
if ([platform isEqualToString:@"iPhone10,1"]) return UIDevice8iPhone;
|
||||
if ([platform isEqualToString:@"iPhone10,4"]) return UIDevice8iPhone;
|
||||
if ([platform isEqualToString:@"iPhone10,2"]) return UIDevice8PlusiPhone;
|
||||
if ([platform isEqualToString:@"iPhone10,5"]) return UIDevice8PlusiPhone;
|
||||
if ([platform isEqualToString:@"iPhone10,3"]) return UIDeviceXiPhone;
|
||||
if ([platform isEqualToString:@"iPhone10,6"]) return UIDeviceXiPhone;
|
||||
if ([platform isEqualToString:@"iPhone11,2"]) return UIDeviceXSiPhone;
|
||||
if ([platform isEqualToString:@"iPhone11,6"]) return UIDeviceXSMaxiPhone;
|
||||
if ([platform isEqualToString:@"iPhone11,4"]) return UIDeviceXSMaxiPhone;
|
||||
if ([platform isEqualToString:@"iPhone11,8"]) return UIDeviceXRiPhone;
|
||||
|
||||
if ([platform isEqualToString:@"iPhone8,4"]) return UIDeviceSEPhone;
|
||||
|
||||
// iPod
|
||||
if ([platform hasPrefix:@"iPod1"]) return UIDevice1GiPod;
|
||||
if ([platform hasPrefix:@"iPod2"]) return UIDevice2GiPod;
|
||||
if ([platform hasPrefix:@"iPod3"]) return UIDevice3GiPod;
|
||||
if ([platform hasPrefix:@"iPod4"]) return UIDevice4GiPod;
|
||||
if ([platform hasPrefix:@"iPod5"]) return UIDevice5GiPod;
|
||||
if ([platform hasPrefix:@"iPod7"]) return UIDevice6GiPod;
|
||||
|
||||
// iPad
|
||||
if ([platform hasPrefix:@"iPad1"]) return UIDevice1GiPad;
|
||||
if ([platform hasPrefix:@"iPad2"]) return UIDevice2GiPad;
|
||||
if ([platform hasPrefix:@"iPad3"]) return UIDevice3GiPad;
|
||||
if ([platform hasPrefix:@"iPad4"]) return UIDevice4GiPad;
|
||||
if ([platform hasPrefix:@"iPad5"]) return UIDevice5GiPad;
|
||||
if ([platform hasPrefix:@"iPad6"]) return UIDevice6GiPad;
|
||||
|
||||
if ([platform isEqualToString:@"iPad8,5"] ||
|
||||
[platform isEqualToString:@"iPad8,6"] ||
|
||||
[platform isEqualToString:@"iPad8,7"] ||
|
||||
[platform isEqualToString:@"iPad8,8"]) {
|
||||
return UIDeviceiPadPro12_93g;
|
||||
}
|
||||
|
||||
if ([platform isEqualToString:@"iPad8,1"] ||
|
||||
[platform isEqualToString:@"iPad8,2"] ||
|
||||
[platform isEqualToString:@"iPad8,3"] ||
|
||||
[platform isEqualToString:@"iPad8,4"]) {
|
||||
return UIDeviceiPadPro11;
|
||||
}
|
||||
|
||||
if ([platform isEqualToString:@"iPad7,5"] ||
|
||||
[platform isEqualToString:@"iPad7,6"]) {
|
||||
return UIDeviceiPadPro6g;
|
||||
}
|
||||
|
||||
if ([platform isEqualToString:@"iPad7,3"] ||
|
||||
[platform isEqualToString:@"iPad7,4"]) {
|
||||
return UIDeviceiPadPro10_5;
|
||||
}
|
||||
|
||||
if ([platform isEqualToString:@"iPad7,1"] ||
|
||||
[platform isEqualToString:@"iPad7,2"]) {
|
||||
return UIDeviceiPadPro12_9;
|
||||
}
|
||||
|
||||
// Apple TV
|
||||
if ([platform hasPrefix:@"AppleTV2"]) return UIDeviceAppleTV2;
|
||||
if ([platform hasPrefix:@"AppleTV3"]) return UIDeviceAppleTV3;
|
||||
|
||||
if ([platform hasPrefix:@"iPhone"]) return UIDeviceUnknowniPhone;
|
||||
if ([platform hasPrefix:@"iPod"]) return UIDeviceUnknowniPod;
|
||||
if ([platform hasPrefix:@"iPad"]) return UIDeviceUnknowniPad;
|
||||
if ([platform hasPrefix:@"AppleTV"]) return UIDeviceUnknownAppleTV;
|
||||
|
||||
#define IPAD_PRO_3G_NAMESTRING @"iPad Pro 12.9 (3rd gen)"
|
||||
#define IPAD_PRO_11_NAMESTRING @"iPad Pro 11"
|
||||
#define IPAD_PRO_6G_NAMESTRING @"iPad (6th gen)"
|
||||
#define IPAD_PRO_10_5_NAMESTRING @"iPad Pro 10.5"
|
||||
#define IPAD_PRO_12_9_NAMESTRING @"iPad Pro 12.9"
|
||||
|
||||
// Simulator thanks Jordan Breeding
|
||||
if ([platform hasSuffix:@"86"] || [platform isEqual:@"x86_64"])
|
||||
{
|
||||
return UIDeviceSimulatoriPhone;
|
||||
}
|
||||
#else
|
||||
return UIDeviceOSX;
|
||||
#endif
|
||||
|
||||
return UIDeviceUnknown;
|
||||
}
|
||||
|
||||
- (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] init];
|
||||
|
||||
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->_socksProxySettings = self.socksProxySettings;
|
||||
result->_networkSettings = self.networkSettings;
|
||||
result->_systemCode = self.systemCode;
|
||||
|
||||
[result _updateApiInitializationHash];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)__unused zone {
|
||||
MTApiEnvironment *result = [[MTApiEnvironment alloc] init];
|
||||
|
||||
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 _updateApiInitializationHash];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (MTApiEnvironment *)withUpdatedSocksProxySettings:(MTSocksProxySettings *)socksProxySettings {
|
||||
MTApiEnvironment *result = [[MTApiEnvironment alloc] init];
|
||||
|
||||
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 _updateApiInitializationHash];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (MTApiEnvironment *)withUpdatedNetworkSettings:(MTNetworkSettings *)networkSettings {
|
||||
MTApiEnvironment *result = [[MTApiEnvironment alloc] init];
|
||||
|
||||
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 _updateApiInitializationHash];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (MTApiEnvironment *)withUpdatedSystemCode:(NSData *)systemCode {
|
||||
MTApiEnvironment *result = [[MTApiEnvironment alloc] init];
|
||||
|
||||
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 _updateApiInitializationHash];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@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
|
18
submodules/MtProtoKit/MTProtoKit/MTBuffer.h
Normal file
18
submodules/MtProtoKit/MTProtoKit/MTBuffer.h
Normal 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
submodules/MtProtoKit/MTProtoKit/MTBuffer.m
Normal file
90
submodules/MtProtoKit/MTProtoKit/MTBuffer.m
Normal 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
|
19
submodules/MtProtoKit/MTProtoKit/MTBufferReader.h
Normal file
19
submodules/MtProtoKit/MTProtoKit/MTBufferReader.h
Normal file
@ -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
|
126
submodules/MtProtoKit/MTProtoKit/MTBufferReader.m
Normal file
126
submodules/MtProtoKit/MTProtoKit/MTBufferReader.m
Normal file
@ -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
|
115
submodules/MtProtoKit/MTProtoKit/MTContext.h
Normal file
115
submodules/MtProtoKit/MTProtoKit/MTContext.h
Normal file
@ -0,0 +1,115 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTDatacenterAuthInfo.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTDatacenterAuthInfo.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTDatacenterAuthInfo.h>
|
||||
#endif
|
||||
|
||||
@class MTDatacenterAddress;
|
||||
@class MTDatacenterAddressSet;
|
||||
@protocol MTSerialization;
|
||||
@class MTContext;
|
||||
@class MTTransportScheme;
|
||||
@protocol MTKeychain;
|
||||
@class MTSessionInfo;
|
||||
@class MTApiEnvironment;
|
||||
@class MTSignal;
|
||||
|
||||
@protocol MTContextChangeListener <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
- (void)contextDatacenterAddressSetUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId addressSet:(MTDatacenterAddressSet *)addressSet;
|
||||
- (void)contextDatacenterAuthInfoUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId authInfo:(MTDatacenterAuthInfo *)authInfo;
|
||||
- (void)contextDatacenterAuthTokenUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId authToken:(id)authToken;
|
||||
- (void)contextDatacenterTransportSchemesUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId;
|
||||
- (void)contextIsPasswordRequiredUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId;
|
||||
- (void)contextDatacenterPublicKeysUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> *)publicKeys;
|
||||
- (MTSignal *)fetchContextDatacenterPublicKeys:(MTContext *)context datacenterId:(NSInteger)datacenterId;
|
||||
- (void)contextApiEnvironmentUpdated:(MTContext *)context apiEnvironment:(MTApiEnvironment *)apiEnvironment;
|
||||
- (MTSignal *)isContextNetworkAccessAllowed:(MTContext *)context;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTContextBlockChangeListener : NSObject <MTContextChangeListener>
|
||||
|
||||
@property (nonatomic, copy) void (^contextIsPasswordRequiredUpdated)(MTContext *, NSInteger);
|
||||
@property (nonatomic, copy) MTSignal *(^fetchContextDatacenterPublicKeys)(MTContext *, NSInteger);
|
||||
@property (nonatomic, copy) MTSignal *(^isContextNetworkAccessAllowed)(MTContext *);
|
||||
|
||||
@end
|
||||
|
||||
@interface MTContext : NSObject
|
||||
|
||||
@property (nonatomic, strong) id<MTKeychain> keychain;
|
||||
|
||||
@property (nonatomic, strong, readonly) id<MTSerialization> serialization;
|
||||
@property (nonatomic, strong, readonly) MTApiEnvironment *apiEnvironment;
|
||||
@property (nonatomic, readonly) bool isTestingEnvironment;
|
||||
@property (nonatomic, readonly) bool useTempAuthKeys;
|
||||
|
||||
- (instancetype)initWithSerialization:(id<MTSerialization>)serialization apiEnvironment:(MTApiEnvironment *)apiEnvironment isTestingEnvironment:(bool)isTestingEnvironment useTempAuthKeys:(bool)useTempAuthKeys;
|
||||
|
||||
- (void)performBatchUpdates:(void (^)())block;
|
||||
|
||||
- (void)addChangeListener:(id<MTContextChangeListener>)changeListener;
|
||||
- (void)removeChangeListener:(id<MTContextChangeListener>)changeListener;
|
||||
|
||||
- (void)setDiscoverBackupAddressListSignal:(MTSignal *)signal;
|
||||
|
||||
- (NSTimeInterval)globalTime;
|
||||
- (NSTimeInterval)globalTimeDifference;
|
||||
- (NSTimeInterval)globalTimeOffsetFromUTC;
|
||||
- (void)setGlobalTimeDifference:(NSTimeInterval)globalTimeDifference;
|
||||
|
||||
- (void)setSeedAddressSetForDatacenterWithId:(NSInteger)datacenterId seedAddressSet:(MTDatacenterAddressSet *)seedAddressSet;
|
||||
- (void)updateAddressSetForDatacenterWithId:(NSInteger)datacenterId addressSet:(MTDatacenterAddressSet *)addressSet forceUpdateSchemes:(bool)forceUpdateSchemes;
|
||||
- (void)addAddressForDatacenterWithId:(NSInteger)datacenterId address:(MTDatacenterAddress *)address;
|
||||
- (void)updateTransportSchemeForDatacenterWithId:(NSInteger)datacenterId transportScheme:(MTTransportScheme *)transportScheme media:(bool)media isProxy:(bool)isProxy;
|
||||
- (void)updateAuthInfoForDatacenterWithId:(NSInteger)datacenterId authInfo:(MTDatacenterAuthInfo *)authInfo;
|
||||
|
||||
- (bool)isPasswordInputRequiredForDatacenterWithId:(NSInteger)datacenterId;
|
||||
- (bool)updatePasswordInputRequiredForDatacenterWithId:(NSInteger)datacenterId required:(bool)required;
|
||||
|
||||
- (void)scheduleSessionCleanupForAuthKeyId:(int64_t)authKeyId sessionInfo:(MTSessionInfo *)sessionInfo;
|
||||
- (void)collectSessionIdsForCleanupWithAuthKeyId:(int64_t)authKeyId completion:(void (^)(NSArray *sessionIds))completion;
|
||||
- (void)sessionIdsDeletedForAuthKeyId:(int64_t)authKeyId sessionIds:(NSArray *)sessionIds;
|
||||
|
||||
- (NSArray *)knownDatacenterIds;
|
||||
- (void)enumerateAddressSetsForDatacenters:(void (^)(NSInteger datacenterId, MTDatacenterAddressSet *addressSet, BOOL *stop))block;
|
||||
|
||||
- (MTDatacenterAddressSet *)addressSetForDatacenterWithId:(NSInteger)datacenterId;
|
||||
- (void)reportTransportSchemeFailureForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme *)transportScheme;
|
||||
- (void)reportTransportSchemeSuccessForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme *)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 *)transportScheme isProbablyHttp:(bool)isProbablyHttp media:(bool)media;
|
||||
- (void)revalidateTransportSchemeForDatacenterId:(NSInteger)datacenterId transportScheme:(MTTransportScheme *)transportScheme media:(bool)media;
|
||||
- (MTDatacenterAuthInfo *)authInfoForDatacenterWithId:(NSInteger)datacenterId;
|
||||
|
||||
- (NSArray<NSDictionary *> *)publicKeysForDatacenterWithId:(NSInteger)datacenterId;
|
||||
- (void)updatePublicKeysForDatacenterWithId:(NSInteger)datacenterId publicKeys:(NSArray<NSDictionary *> *)publicKeys;
|
||||
- (void)publicKeysForDatacenterWithIdRequired:(NSInteger)datacenterId;
|
||||
|
||||
- (void)removeAllAuthTokens;
|
||||
- (id)authTokenForDatacenterWithId:(NSInteger)datacenterId;
|
||||
- (void)updateAuthTokenForDatacenterWithId:(NSInteger)datacenterId authToken:(id)authToken;
|
||||
|
||||
- (void)addressSetForDatacenterWithIdRequired:(NSInteger)datacenterId;
|
||||
- (void)authInfoForDatacenterWithIdRequired:(NSInteger)datacenterId isCdn:(bool)isCdn;
|
||||
- (void)tempAuthKeyForDatacenterWithIdRequired:(NSInteger)datacenterId keyType:(MTDatacenterAuthTempKeyType)keyType;
|
||||
- (void)authTokenForDatacenterWithIdRequired:(NSInteger)datacenterId authToken:(id)authToken masterDatacenterId:(NSInteger)masterDatacenterId;
|
||||
|
||||
- (void)reportProblemsWithDatacenterAddressForId:(NSInteger)datacenterId address:(MTDatacenterAddress *)address;
|
||||
|
||||
- (void)updateApiEnvironment:(MTApiEnvironment *(^)(MTApiEnvironment *))f;
|
||||
|
||||
- (void)beginExplicitBackupAddressDiscovery;
|
||||
|
||||
@end
|
1362
submodules/MtProtoKit/MTProtoKit/MTContext.m
Normal file
1362
submodules/MtProtoKit/MTProtoKit/MTContext.m
Normal file
File diff suppressed because it is too large
Load Diff
21
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddress.h
Normal file
21
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddress.h
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTDatacenterAddress : NSObject <NSCoding, NSCopying>
|
||||
|
||||
@property (nonatomic, strong, readonly) NSString *host;
|
||||
@property (nonatomic, strong, readonly) NSString *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 *secret;
|
||||
|
||||
- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy secret:(NSData *)secret;
|
||||
|
||||
- (BOOL)isEqualToAddress:(MTDatacenterAddress *)other;
|
||||
- (BOOL)isIpv6;
|
||||
|
||||
@end
|
124
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddress.m
Normal file
124
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddress.m
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
|
||||
#import "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,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,19 @@
|
||||
#import "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
|
15
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddressSet.h
Normal file
15
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddressSet.h
Normal file
@ -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
|
71
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddressSet.m
Normal file
71
submodules/MtProtoKit/MTProtoKit/MTDatacenterAddressSet.m
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
|
||||
#import "MTDatacenterAddressSet.h"
|
||||
|
||||
#import "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
|
30
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthAction.h
Normal file
30
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthAction.h
Normal file
@ -0,0 +1,30 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTDatacenterAuthInfo.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTDatacenterAuthInfo.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTDatacenterAuthInfo.h>
|
||||
#endif
|
||||
|
||||
@class MTContext;
|
||||
@class MTDatacenterAuthAction;
|
||||
|
||||
@protocol MTDatacenterAuthActionDelegate <NSObject>
|
||||
|
||||
- (void)datacenterAuthActionCompleted:(MTDatacenterAuthAction *)action;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTDatacenterAuthAction : NSObject
|
||||
|
||||
@property (nonatomic, readonly) bool tempAuth;
|
||||
@property (nonatomic, weak) id<MTDatacenterAuthActionDelegate> delegate;
|
||||
|
||||
- (instancetype)initWithTempAuth:(bool)tempAuth tempAuthKeyType:(MTDatacenterAuthTempKeyType)tempAuthKeyType;
|
||||
|
||||
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId isCdn:(bool)isCdn;
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
165
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthAction.m
Normal file
165
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthAction.m
Normal file
@ -0,0 +1,165 @@
|
||||
#import "MTDatacenterAuthAction.h"
|
||||
|
||||
#import "MTLogging.h"
|
||||
#import "MTContext.h"
|
||||
#import "MTProto.h"
|
||||
#import "MTRequest.h"
|
||||
#import "MTDatacenterSaltInfo.h"
|
||||
#import "MTDatacenterAuthInfo.h"
|
||||
#import "MTApiEnvironment.h"
|
||||
#import "MTSerialization.h"
|
||||
#import "MTDatacenterAddressSet.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTSignal.h>
|
||||
#endif
|
||||
|
||||
#import "MTDatacenterAuthMessageService.h"
|
||||
#import "MTRequestMessageService.h"
|
||||
|
||||
#import "MTBuffer.h"
|
||||
|
||||
@interface MTDatacenterAuthAction () <MTDatacenterAuthMessageServiceDelegate>
|
||||
{
|
||||
bool _isCdn;
|
||||
MTDatacenterAuthTempKeyType _tempAuthKeyType;
|
||||
|
||||
NSInteger _datacenterId;
|
||||
__weak MTContext *_context;
|
||||
|
||||
bool _awaitingAddresSetUpdate;
|
||||
MTProto *_authMtProto;
|
||||
|
||||
MTMetaDisposable *_verifyDisposable;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDatacenterAuthAction
|
||||
|
||||
- (instancetype)initWithTempAuth:(bool)tempAuth tempAuthKeyType:(MTDatacenterAuthTempKeyType)tempAuthKeyType {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_tempAuth = tempAuth;
|
||||
_tempAuthKeyType = tempAuthKeyType;
|
||||
_verifyDisposable = [[MTMetaDisposable alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self cleanup];
|
||||
}
|
||||
|
||||
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId isCdn:(bool)isCdn
|
||||
{
|
||||
_datacenterId = datacenterId;
|
||||
_context = context;
|
||||
_isCdn = isCdn;
|
||||
|
||||
if (_datacenterId != 0 && context != nil)
|
||||
{
|
||||
bool alreadyCompleted = false;
|
||||
MTDatacenterAuthInfo *currentAuthInfo = [context authInfoForDatacenterWithId:_datacenterId];
|
||||
if (currentAuthInfo != nil) {
|
||||
if (_tempAuth) {
|
||||
if ([currentAuthInfo tempAuthKeyWithType:_tempAuthKeyType] != nil) {
|
||||
alreadyCompleted = true;
|
||||
}
|
||||
} else {
|
||||
alreadyCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyCompleted) {
|
||||
[self complete];
|
||||
} else {
|
||||
_authMtProto = [[MTProto alloc] initWithContext:context datacenterId:_datacenterId usageCalculationInfo:nil];
|
||||
_authMtProto.cdn = isCdn;
|
||||
_authMtProto.useUnauthorizedMode = true;
|
||||
if (_tempAuth) {
|
||||
switch (_tempAuthKeyType) {
|
||||
case MTDatacenterAuthTempKeyTypeMain:
|
||||
_authMtProto.media = false;
|
||||
break;
|
||||
case MTDatacenterAuthTempKeyTypeMedia:
|
||||
_authMtProto.media = true;
|
||||
_authMtProto.enforceMedia = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MTDatacenterAuthMessageService *authService = [[MTDatacenterAuthMessageService alloc] initWithContext:context tempAuth:_tempAuth];
|
||||
authService.delegate = self;
|
||||
[_authMtProto addMessageService:authService];
|
||||
}
|
||||
}
|
||||
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 (_tempAuth) {
|
||||
MTContext *mainContext = _context;
|
||||
if (mainContext != nil) {
|
||||
MTContext *context = _context;
|
||||
[context performBatchUpdates:^{
|
||||
MTDatacenterAuthInfo *authInfo = [context authInfoForDatacenterWithId:_datacenterId];
|
||||
if (authInfo != nil) {
|
||||
authInfo = [authInfo withUpdatedTempAuthKeyWithType:_tempAuthKeyType key:authKey];
|
||||
[context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo];
|
||||
}
|
||||
}];
|
||||
[self complete];
|
||||
}
|
||||
} else {
|
||||
MTDatacenterAuthInfo *authInfo = [[MTDatacenterAuthInfo alloc] initWithAuthKey:authKey.authKey authKeyId:authKey.authKeyId saltSet:@[[[MTDatacenterSaltInfo alloc] initWithSalt:0 firstValidMessageId:timestamp lastValidMessageId:timestamp + (29.0 * 60.0) * 4294967296]] authKeyAttributes:nil mainTempAuthKey:nil mediaTempAuthKey:nil];
|
||||
|
||||
MTContext *context = _context;
|
||||
[context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo];
|
||||
[self complete];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
MTProto *authMtProto = _authMtProto;
|
||||
_authMtProto = nil;
|
||||
|
||||
[authMtProto stop];
|
||||
|
||||
[_verifyDisposable dispose];
|
||||
}
|
||||
|
||||
- (void)cancel
|
||||
{
|
||||
[self cleanup];
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)complete
|
||||
{
|
||||
id<MTDatacenterAuthActionDelegate> delegate = _delegate;
|
||||
if ([delegate respondsToSelector:@selector(datacenterAuthActionCompleted:)])
|
||||
[delegate datacenterAuthActionCompleted:self];
|
||||
}
|
||||
|
||||
- (void)fail
|
||||
{
|
||||
id<MTDatacenterAuthActionDelegate> delegate = _delegate;
|
||||
if ([delegate respondsToSelector:@selector(datacenterAuthActionCompleted:)])
|
||||
[delegate datacenterAuthActionCompleted:self];
|
||||
}
|
||||
|
||||
@end
|
38
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthInfo.h
Normal file
38
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthInfo.h
Normal file
@ -0,0 +1,38 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MTDatacenterAuthTempKeyType) {
|
||||
MTDatacenterAuthTempKeyTypeMain,
|
||||
MTDatacenterAuthTempKeyTypeMedia
|
||||
};
|
||||
|
||||
@interface MTDatacenterAuthKey: NSObject <NSCoding>
|
||||
|
||||
@property (nonatomic, strong, readonly) NSData *authKey;
|
||||
@property (nonatomic, readonly) int64_t authKeyId;
|
||||
@property (nonatomic, readonly) bool notBound;
|
||||
|
||||
- (instancetype)initWithAuthKey:(NSData *)tempAuthKey authKeyId:(int64_t)authKeyId notBound:(bool)notBound;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTDatacenterAuthInfo : NSObject <NSCoding>
|
||||
|
||||
@property (nonatomic, strong, readonly) NSData *authKey;
|
||||
@property (nonatomic, readonly) int64_t authKeyId;
|
||||
@property (nonatomic, strong, readonly) NSArray *saltSet;
|
||||
@property (nonatomic, strong, readonly) NSDictionary *authKeyAttributes;
|
||||
@property (nonatomic, strong, readonly) MTDatacenterAuthKey *mainTempAuthKey;
|
||||
@property (nonatomic, strong, readonly) MTDatacenterAuthKey *mediaTempAuthKey;
|
||||
|
||||
@property (nonatomic, strong, readonly) MTDatacenterAuthKey *persistentAuthKey;
|
||||
|
||||
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId saltSet:(NSArray *)saltSet authKeyAttributes:(NSDictionary *)authKeyAttributes mainTempAuthKey:(MTDatacenterAuthKey *)mainTempAuthKey mediaTempAuthKey:(MTDatacenterAuthKey *)mediaTempAuthKey;
|
||||
|
||||
- (int64_t)authSaltForMessageId:(int64_t)messageId;
|
||||
- (MTDatacenterAuthInfo *)mergeSaltSet:(NSArray *)updatedSaltSet forTimestamp:(NSTimeInterval)timestamp;
|
||||
|
||||
- (MTDatacenterAuthInfo *)withUpdatedAuthKeyAttributes:(NSDictionary *)authKeyAttributes;
|
||||
- (MTDatacenterAuthKey *)tempAuthKeyWithType:(MTDatacenterAuthTempKeyType)type;
|
||||
- (MTDatacenterAuthInfo *)withUpdatedTempAuthKeyWithType:(MTDatacenterAuthTempKeyType)type key:(MTDatacenterAuthKey *)key;
|
||||
|
||||
@end
|
155
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthInfo.m
Normal file
155
submodules/MtProtoKit/MTProtoKit/MTDatacenterAuthInfo.m
Normal file
@ -0,0 +1,155 @@
|
||||
#import "MTDatacenterAuthInfo.h"
|
||||
#import "MTDatacenterSaltInfo.h"
|
||||
|
||||
@implementation MTDatacenterAuthKey
|
||||
|
||||
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId notBound:(bool)notBound {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_authKey = authKey;
|
||||
_authKeyId = authKeyId;
|
||||
_notBound = notBound;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
return [self initWithAuthKey:[aDecoder decodeObjectForKey:@"key"] authKeyId:[aDecoder decodeInt64ForKey:@"keyId"] notBound:[aDecoder decodeBoolForKey:@"notBound"]];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_authKey forKey:@"key"];
|
||||
[aCoder encodeInt64:_authKeyId forKey:@"keyId"];
|
||||
[aCoder encodeBool:_notBound forKey:@"notBound"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDatacenterAuthInfo
|
||||
|
||||
- (instancetype)initWithAuthKey:(NSData *)authKey authKeyId:(int64_t)authKeyId saltSet:(NSArray *)saltSet authKeyAttributes:(NSDictionary *)authKeyAttributes mainTempAuthKey:(MTDatacenterAuthKey *)mainTempAuthKey mediaTempAuthKey:(MTDatacenterAuthKey *)mediaTempAuthKey
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_authKey = authKey;
|
||||
_authKeyId = authKeyId;
|
||||
_saltSet = saltSet;
|
||||
_authKeyAttributes = authKeyAttributes;
|
||||
_mainTempAuthKey = mainTempAuthKey;
|
||||
_mediaTempAuthKey = mediaTempAuthKey;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_authKey = [aDecoder decodeObjectForKey:@"authKey"];
|
||||
_authKeyId = [aDecoder decodeInt64ForKey:@"authKeyId"];
|
||||
_saltSet = [aDecoder decodeObjectForKey:@"saltSet"];
|
||||
_authKeyAttributes = [aDecoder decodeObjectForKey:@"authKeyAttributes"];
|
||||
_mainTempAuthKey = [aDecoder decodeObjectForKey:@"tempAuthKey"];
|
||||
_mediaTempAuthKey = [aDecoder decodeObjectForKey:@"mediaTempAuthKey"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder
|
||||
{
|
||||
[aCoder encodeObject:_authKey forKey:@"authKey"];
|
||||
[aCoder encodeInt64:_authKeyId forKey:@"authKeyId"];
|
||||
[aCoder encodeObject:_saltSet forKey:@"saltSet"];
|
||||
[aCoder encodeObject:_authKeyAttributes forKey:@"authKeyAttributes"];
|
||||
[aCoder encodeObject:_mainTempAuthKey forKey:@"tempAuthKey"];
|
||||
[aCoder encodeObject:_mediaTempAuthKey forKey:@"mediaTempAuthKey"];
|
||||
}
|
||||
|
||||
- (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 saltSet:mergedSaltSet authKeyAttributes:_authKeyAttributes mainTempAuthKey:_mainTempAuthKey mediaTempAuthKey:_mediaTempAuthKey];
|
||||
}
|
||||
|
||||
- (MTDatacenterAuthInfo *)withUpdatedAuthKeyAttributes:(NSDictionary *)authKeyAttributes {
|
||||
return [[MTDatacenterAuthInfo alloc] initWithAuthKey:_authKey authKeyId:_authKeyId saltSet:_saltSet authKeyAttributes:authKeyAttributes mainTempAuthKey:_mainTempAuthKey mediaTempAuthKey:_mediaTempAuthKey];
|
||||
}
|
||||
|
||||
- (MTDatacenterAuthKey *)tempAuthKeyWithType:(MTDatacenterAuthTempKeyType)type {
|
||||
switch (type) {
|
||||
case MTDatacenterAuthTempKeyTypeMain:
|
||||
return _mainTempAuthKey;
|
||||
case MTDatacenterAuthTempKeyTypeMedia:
|
||||
return _mediaTempAuthKey;
|
||||
default:
|
||||
NSAssert(false, @"unknown MTDatacenterAuthTempKeyType");
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (MTDatacenterAuthInfo *)withUpdatedTempAuthKeyWithType:(MTDatacenterAuthTempKeyType)type key:(MTDatacenterAuthKey *)key {
|
||||
switch (type) {
|
||||
case MTDatacenterAuthTempKeyTypeMain:
|
||||
return [[MTDatacenterAuthInfo alloc] initWithAuthKey:_authKey authKeyId:_authKeyId saltSet:_saltSet authKeyAttributes:_authKeyAttributes mainTempAuthKey:key mediaTempAuthKey:_mediaTempAuthKey];
|
||||
case MTDatacenterAuthTempKeyTypeMedia:
|
||||
return [[MTDatacenterAuthInfo alloc] initWithAuthKey:_authKey authKeyId:_authKeyId saltSet:_saltSet authKeyAttributes:_authKeyAttributes mainTempAuthKey:_mainTempAuthKey mediaTempAuthKey:key];
|
||||
default:
|
||||
NSAssert(false, @"unknown MTDatacenterAuthTempKeyType");
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
- (MTDatacenterAuthKey *)persistentAuthKey {
|
||||
return [[MTDatacenterAuthKey alloc] initWithAuthKey:_authKey authKeyId:_authKeyId notBound:false];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"MTDatacenterAuthInfo authKeyId:%" PRId64 " authKey:%lu", _authKeyId, (unsigned long)_authKey.length];
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,27 @@
|
||||
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTMessageService.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTMessageService.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTMessageService.h>
|
||||
#endif
|
||||
|
||||
@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,789 @@
|
||||
#import "MTDatacenterAuthMessageService.h"
|
||||
|
||||
#import "MTLogging.h"
|
||||
#import "MTContext.h"
|
||||
#import "MTProto.h"
|
||||
#import "MTSerialization.h"
|
||||
#import "MTSessionInfo.h"
|
||||
#import "MTIncomingMessage.h"
|
||||
#import "MTOutgoingMessage.h"
|
||||
#import "MTMessageTransaction.h"
|
||||
#import "MTPreparedMessage.h"
|
||||
#import "MTDatacenterAuthInfo.h"
|
||||
#import "MTDatacenterSaltInfo.h"
|
||||
#import "MTBuffer.h"
|
||||
#import "MTEncryption.h"
|
||||
|
||||
#import "MTInternalMessageParser.h"
|
||||
#import "MTServerDhInnerDataMessage.h"
|
||||
#import "MTResPqMessage.h"
|
||||
#import "MTServerDhParamsMessage.h"
|
||||
#import "MTSetClientDhParamsResponseMessage.h"
|
||||
|
||||
static NSArray *defaultPublicKeys() {
|
||||
static NSArray *serverPublicKeys = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
serverPublicKeys = [[NSArray alloc] initWithObjects:
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt\n"
|
||||
"ksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru\n"
|
||||
"vCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L\n"
|
||||
"xI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi\n"
|
||||
"XvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp\n"
|
||||
"NTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0x9a996a1db11c729bUL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+\n"
|
||||
"DyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB\n"
|
||||
"1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s\n"
|
||||
"g1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z\n"
|
||||
"hRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f\n"
|
||||
"x5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0xb05b2a6f70cdea78UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n"
|
||||
"lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\n"
|
||||
"an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\n"
|
||||
"Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n"
|
||||
"8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n"
|
||||
"Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0xc3b42b026ce86b21UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa\n"
|
||||
"xDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i\n"
|
||||
"qAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc\n"
|
||||
"/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks\n"
|
||||
"WV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t\n"
|
||||
"UiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0x71e025b6c76033e3UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAruw2yP/BCcsJliRoW5eBVBVle9dtjJw+OYED160Wybum9SXtBBLX\n"
|
||||
"riwt4rROd9csv0t0OHCaTmRqBcQ0J8fxhN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/\n"
|
||||
"j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvdl84Kd9ORYjDEAyFnEA7dD556OptgLQQ2\n"
|
||||
"e2iVNq8NZLYTzLp5YpOdO1doK+ttrltggTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnS\n"
|
||||
"Lj16yE5HvJQn0CNpRdENvRUXe6tBP78O39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wF\n"
|
||||
"XGF710w9lwCGNbmNxNYhtIkdqfsEcwR5JwIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0xbc35f3509f7b7a5UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAvfLHfYH2r9R70w8prHblWt/nDkh+XkgpflqQVcnAfSuTtO05lNPs\n"
|
||||
"pQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOOKPi0OfJXoRVylFzAQG/j83u5K3kRLbae\n"
|
||||
"7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ3TDS2pQOCtovG4eDl9wacrXOJTG2990V\n"
|
||||
"jgnIKNA0UMoP+KF03qzryqIt3oTvZq03DyWdGK+AZjgBLaDKSnC6qD2cFY81UryR\n"
|
||||
"WOab8zKkWAnhw2kFpcqhI0jdV5QaSCExvnsjVaX0Y1N0870931/5Jb9ICe4nweZ9\n"
|
||||
"kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV/wIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0x15ae5fa8b5529542UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAs/ditzm+mPND6xkhzwFIz6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGr\n"
|
||||
"zqTDHkO30R8VeRM/Kz2f4nR05GIFiITl4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+\n"
|
||||
"th6knSU0yLtNKuQVP6voMrnt9MV1X92LGZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvS\n"
|
||||
"Uwwc+yi1/gGaybwlzZwqXYoPOhwMebzKUk0xW14htcJrRrq+PXXQbRzTMynseCoP\n"
|
||||
"Ioke0dtCodbA3qQxQovE16q9zz4Otv2k4j63cz53J+mhkVWAeWxVGI0lltJmWtEY\n"
|
||||
"K6er8VqqWot3nqmWMXogrgRLggv/NbbooQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0xaeae98e13cd7f94fUL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q05shjg8/4p6047bn6/m8yPy1RBsvIyvuD\n"
|
||||
"uGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xbnfxL5BXHplJhMtADXKM9bWB11PU1Eioc\n"
|
||||
"3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvi\n"
|
||||
"fRLJbY08/Gp66KpQvy7g8w7VB8wlgePexW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqe\n"
|
||||
"Pji9NP3tJUFQjcECqcm0yV7/2d0t/pbCm+ZH1sadZspQCEPPrtbkQBlvHb4OLiIW\n"
|
||||
"PGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6MAQIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0x5a181b2235057d98UL], @"fingerprint", nil],
|
||||
[[NSDictionary alloc] initWithObjectsAndKeys:@"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIIBCgKCAQEAr4v4wxMDXIaMOh8bayF/NyoYdpcysn5EbjTIOZC0RkgzsRj3SGlu\n"
|
||||
"52QSz+ysO41dQAjpFLgxPVJoOlxXokaOq827IfW0bGCm0doT5hxtedu9UCQKbE8j\n"
|
||||
"lDOk+kWMXHPZFJKWRgKgTu9hcB3y3Vk+JFfLpq3d5ZB48B4bcwrRQnzkx5GhWOFX\n"
|
||||
"x73ZgjO93eoQ2b/lDyXxK4B4IS+hZhjzezPZTI5upTRbs5ljlApsddsHrKk6jJNj\n"
|
||||
"8Ygs/ps8e6ct82jLXbnndC9s8HjEvDvBPH9IPjv5JUlmHMBFZ5vFQIfbpo0u0+1P\n"
|
||||
"n6bkEi5o7/ifoyVv2pAZTRwppTz0EuXD8QIDAQAB\n"
|
||||
"-----END RSA PUBLIC KEY-----", @"key", [[NSNumber alloc] initWithUnsignedLongLong:0x9692106da14b9f02UL], @"fingerprint", nil],
|
||||
nil];
|
||||
});
|
||||
return serverPublicKeys;
|
||||
}
|
||||
|
||||
static NSDictionary *selectPublicKey(NSArray *fingerprints, NSArray<NSDictionary *> *publicKeys)
|
||||
{
|
||||
for (NSNumber *nFingerprint in fingerprints)
|
||||
{
|
||||
for (NSDictionary *keyDesc in publicKeys)
|
||||
{
|
||||
int64_t keyFingerprint = [[keyDesc objectForKey:@"fingerprint"] longLongValue];
|
||||
|
||||
if ([nFingerprint longLongValue] == keyFingerprint)
|
||||
return keyDesc;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MTDatacenterAuthStageWaitingForPublicKeys = 0,
|
||||
MTDatacenterAuthStagePQ = 1,
|
||||
MTDatacenterAuthStageReqDH = 2,
|
||||
MTDatacenterAuthStageKeyVerification = 3,
|
||||
MTDatacenterAuthStageDone = 4
|
||||
} MTDatacenterAuthStage;
|
||||
|
||||
@interface MTDatacenterAuthMessageService ()
|
||||
{
|
||||
bool _tempAuth;
|
||||
MTSessionInfo *_sessionInfo;
|
||||
|
||||
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<NSDictionary *> *_publicKeys;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDatacenterAuthMessageService
|
||||
|
||||
- (instancetype)initWithContext:(MTContext *)context tempAuth:(bool)tempAuth
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_tempAuth = tempAuth;
|
||||
_sessionInfo = [[MTSessionInfo alloc] initWithRandomSessionIdAndContext:context];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (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 = [mtProto.context publicKeysForDatacenterWithId:mtProto.datacenterId];
|
||||
if (_publicKeys == nil) {
|
||||
_stage = MTDatacenterAuthStageWaitingForPublicKeys;
|
||||
[mtProto.context publicKeysForDatacenterWithIdRequired:mtProto.datacenterId];
|
||||
} else {
|
||||
_stage = MTDatacenterAuthStagePQ;
|
||||
}
|
||||
} else {
|
||||
_publicKeys = defaultPublicKeys();
|
||||
_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 (_stage == MTDatacenterAuthStageWaitingForPublicKeys) {
|
||||
if (mtProto.datacenterId == datacenterId) {
|
||||
_publicKeys = publicKeys;
|
||||
if (_publicKeys != nil && _publicKeys.count != 0) {
|
||||
_stage = MTDatacenterAuthStagePQ;
|
||||
[mtProto requestTransportTransaction];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (MTMessageTransaction *)mtProtoMessageTransaction:(MTProto *)mtProto
|
||||
{
|
||||
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)0x60469778];
|
||||
[reqPqBuffer appendBytes:_nonce.bytes length:_nonce.length];
|
||||
|
||||
NSString *messageDescription = [NSString stringWithFormat:@"reqPq nonce:%@", _nonce];
|
||||
MTOutgoingMessage *message = [[MTOutgoingMessage alloc] initWithData:reqPqBuffer.data metadata:messageDescription 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:
|
||||
{
|
||||
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", _nonce, _serverNonce, _dhP, _dhQ, _dhPublicKeyFingerprint];
|
||||
MTOutgoingMessage *message = [[MTOutgoingMessage alloc] initWithData:reqDhBuffer.data metadata:messageDescription 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" 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;
|
||||
}
|
||||
|
||||
- (void)mtProto:(MTProto *)mtProto receivedMessage:(MTIncomingMessage *)message
|
||||
{
|
||||
if (_stage == MTDatacenterAuthStagePQ && [message.body isKindOfClass:[MTResPqMessage class]])
|
||||
{
|
||||
MTResPqMessage *resPqMessage = message.body;
|
||||
|
||||
if ([_nonce isEqualToData:resPqMessage.nonce])
|
||||
{
|
||||
NSDictionary *publicKey = selectPublicKey(resPqMessage.serverPublicKeyFingerprints, _publicKeys);
|
||||
|
||||
if (publicKey == nil && mtProto.cdn && resPqMessage.serverPublicKeyFingerprints.count == 1 && _publicKeys.count == 1) {
|
||||
publicKey = @{@"key": _publicKeys[0][@"key"], @"fingerprint": resPqMessage.serverPublicKeyFingerprints[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 objectForKey:@"fingerprint"] longLongValue];
|
||||
|
||||
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:60 * 60 * 32];
|
||||
|
||||
NSData *innerDataBytes = innerDataBuffer.data;
|
||||
|
||||
NSMutableData *dataWithHash = [[NSMutableData alloc] init];
|
||||
[dataWithHash appendData:MTSha1(innerDataBytes)];
|
||||
[dataWithHash appendData:innerDataBytes];
|
||||
while (dataWithHash.length < 255)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[dataWithHash appendBytes:&random length:1];
|
||||
}
|
||||
|
||||
NSData *encryptedData = MTRsaEncrypt([publicKey objectForKey:@"key"], dataWithHash);
|
||||
if (encryptedData.length < 256)
|
||||
{
|
||||
NSMutableData *newEncryptedData = [[NSMutableData alloc] init];
|
||||
for (int i = 0; i < 256 - (int)encryptedData.length; i++)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[newEncryptedData appendBytes:&random length:1];
|
||||
}
|
||||
[newEncryptedData appendData:encryptedData];
|
||||
encryptedData = newEncryptedData;
|
||||
}
|
||||
|
||||
_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;
|
||||
|
||||
NSMutableData *dataWithHash = [[NSMutableData alloc] init];
|
||||
[dataWithHash appendData:MTSha1(innerDataBytes)];
|
||||
[dataWithHash appendData:innerDataBytes];
|
||||
while (dataWithHash.length < 255)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[dataWithHash appendBytes:&random length:1];
|
||||
}
|
||||
|
||||
NSData *encryptedData = MTRsaEncrypt([publicKey objectForKey:@"key"], dataWithHash);
|
||||
if (encryptedData.length < 256)
|
||||
{
|
||||
NSMutableData *newEncryptedData = [[NSMutableData alloc] init];
|
||||
for (int i = 0; i < 256 - (int)encryptedData.length; i++)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[newEncryptedData appendBytes:&random length:1];
|
||||
}
|
||||
[newEncryptedData appendData:encryptedData];
|
||||
encryptedData = newEncryptedData;
|
||||
}
|
||||
|
||||
_dhEncryptedData = encryptedData;
|
||||
}
|
||||
|
||||
_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(innerDataGA, innerDataDhPrime))
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g_a]", self);
|
||||
}
|
||||
[self reset:mtProto];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MTCheckMod(innerDataDhPrime, (unsigned int)innerDataG, mtProto.context.keychain))
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTDatacenterAuthMessageService#%p invalid DH g (2)]", self);
|
||||
}
|
||||
[self reset:mtProto];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MTCheckIsSafePrime(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(g, b, innerDataDhPrime);
|
||||
|
||||
NSData *authKey = MTExp(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];
|
||||
}
|
||||
|
||||
_authKey = [[MTDatacenterAuthKey alloc] initWithAuthKey:authKey authKeyId:authKeyId 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
|
16
submodules/MtProtoKit/MTProtoKit/MTDatacenterSaltInfo.h
Normal file
16
submodules/MtProtoKit/MTProtoKit/MTDatacenterSaltInfo.h
Normal file
@ -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
|
51
submodules/MtProtoKit/MTProtoKit/MTDatacenterSaltInfo.m
Normal file
51
submodules/MtProtoKit/MTProtoKit/MTDatacenterSaltInfo.m
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
#import "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,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,185 @@
|
||||
|
||||
|
||||
#import "MTDatacenterTransferAuthAction.h"
|
||||
|
||||
#import "MTContext.h"
|
||||
#import "MTSerialization.h"
|
||||
#import "MTProto.h"
|
||||
#import "MTRequestMessageService.h"
|
||||
#import "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];
|
||||
_sourceDatacenterMtProto.useTempAuthKeys = context.useTempAuthKeys;
|
||||
|
||||
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
|
||||
requestService.forceBackgroundRequests = true;
|
||||
[_sourceDatacenterMtProto addMessageService:requestService];
|
||||
|
||||
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 NSTimeInterval timestamp, 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:(int32_t)dataId data:(NSData *)authData
|
||||
{
|
||||
[_sourceDatacenterMtProto stop];
|
||||
_sourceDatacenterMtProto = nil;
|
||||
|
||||
MTContext *context = _context;
|
||||
_destinationDatacenterMtProto = [[MTProto alloc] initWithContext:context datacenterId:_destinationDatacenterId usageCalculationInfo:nil];
|
||||
_destinationDatacenterMtProto.useTempAuthKeys = context.useTempAuthKeys;
|
||||
|
||||
MTRequestMessageService *requestService = [[MTRequestMessageService alloc] initWithContext:context];
|
||||
requestService.forceBackgroundRequests = true;
|
||||
[_destinationDatacenterMtProto addMessageService:requestService];
|
||||
|
||||
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 NSTimeInterval timestamp, 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,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,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
|
@ -0,0 +1,185 @@
|
||||
|
||||
|
||||
#import "MTDiscoverDatacenterAddressAction.h"
|
||||
|
||||
#import "MTContext.h"
|
||||
#import "MTSerialization.h"
|
||||
#import "MTProto.h"
|
||||
#import "MTDatacenterAddressSet.h"
|
||||
#import "MTRequestMessageService.h"
|
||||
#import "MTRequest.h"
|
||||
|
||||
@interface MTDiscoverDatacenterAddressAction () <MTContextChangeListener>
|
||||
{
|
||||
NSInteger _datacenterId;
|
||||
__weak MTContext *_context;
|
||||
|
||||
NSInteger _targetDatacenterId;
|
||||
bool _awaitingAddresSetUpdate;
|
||||
MTProto *_mtProto;
|
||||
MTRequestMessageService *_requestService;
|
||||
|
||||
NSMutableSet *_processedDatacenters;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDiscoverDatacenterAddressAction
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_processedDatacenters = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self cleanup];
|
||||
}
|
||||
|
||||
- (void)execute:(MTContext *)context datacenterId:(NSInteger)datacenterId
|
||||
{
|
||||
_datacenterId = datacenterId;
|
||||
_context = context;
|
||||
|
||||
if (_datacenterId != 0 && context != nil)
|
||||
{
|
||||
__block bool datacenterAddressIsKnown = false;
|
||||
__block NSInteger currentDatacenterId = 0;
|
||||
|
||||
[context enumerateAddressSetsForDatacenters:^(NSInteger datacenterId, __unused MTDatacenterAddressSet *addressSet, BOOL *stop)
|
||||
{
|
||||
if (datacenterId == _datacenterId)
|
||||
{
|
||||
datacenterAddressIsKnown = true;
|
||||
if (stop != NULL)
|
||||
*stop = true;
|
||||
}
|
||||
else if (![_processedDatacenters containsObject:@(datacenterId)])
|
||||
{
|
||||
currentDatacenterId = datacenterId;
|
||||
[_processedDatacenters addObject:@(datacenterId)];
|
||||
|
||||
if (stop != NULL)
|
||||
*stop = true;
|
||||
}
|
||||
}];
|
||||
|
||||
if (datacenterAddressIsKnown)
|
||||
[self complete];
|
||||
else if (currentDatacenterId != 0)
|
||||
[self askForAnAddressDatacenterWithId:currentDatacenterId useTempAuthKeys:context.useTempAuthKeys];
|
||||
else
|
||||
[self fail];
|
||||
}
|
||||
else
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)askForAnAddressDatacenterWithId:(NSInteger)targetDatacenterId useTempAuthKeys:(bool)useTempAuthKeys
|
||||
{
|
||||
_targetDatacenterId = targetDatacenterId;
|
||||
|
||||
MTContext *context = _context;
|
||||
|
||||
if (context == nil)
|
||||
[self fail];
|
||||
else
|
||||
{
|
||||
if ([context authInfoForDatacenterWithId:_targetDatacenterId] != nil)
|
||||
{
|
||||
_mtProto = [[MTProto alloc] initWithContext:context datacenterId:_targetDatacenterId usageCalculationInfo:nil];
|
||||
_mtProto.useTempAuthKeys = useTempAuthKeys;
|
||||
_requestService = [[MTRequestMessageService alloc] initWithContext:_context];
|
||||
_requestService.forceBackgroundRequests = true;
|
||||
[_mtProto addMessageService:_requestService];
|
||||
|
||||
MTRequest *request = [[MTRequest alloc] init];
|
||||
|
||||
NSData *getConfigData = nil;
|
||||
MTRequestDatacenterAddressListParser responseParser = [_context.serialization requestDatacenterAddressWithData:&getConfigData];
|
||||
|
||||
[request setPayload:getConfigData metadata:@"getConfig" shortMetadata:@"getConfig" responseParser:responseParser];
|
||||
|
||||
__weak MTDiscoverDatacenterAddressAction *weakSelf = self;
|
||||
[request setCompleted:^(MTDatacenterAddressListData *result, __unused NSTimeInterval completionTimestamp, id error)
|
||||
{
|
||||
__strong MTDiscoverDatacenterAddressAction *strongSelf = weakSelf;
|
||||
if (strongSelf != nil) {
|
||||
if (error == nil)
|
||||
[strongSelf getConfigSuccess:result.addressList[@(strongSelf->_datacenterId)]];
|
||||
else
|
||||
[strongSelf getConfigFailed];
|
||||
}
|
||||
}];
|
||||
|
||||
[_requestService addRequest:request];
|
||||
}
|
||||
else
|
||||
[context authInfoForDatacenterWithIdRequired:_targetDatacenterId isCdn:false];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)contextDatacenterAuthInfoUpdated:(MTContext *)context datacenterId:(NSInteger)datacenterId authInfo:(MTDatacenterAuthInfo *)__unused authInfo
|
||||
{
|
||||
if (_context != context || !_awaitingAddresSetUpdate)
|
||||
return;
|
||||
|
||||
if (_targetDatacenterId != 0 && _targetDatacenterId == datacenterId)
|
||||
{
|
||||
_awaitingAddresSetUpdate = false;
|
||||
|
||||
[self askForAnAddressDatacenterWithId:datacenterId useTempAuthKeys:context.useTempAuthKeys];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getConfigSuccess:(NSArray *)addressList
|
||||
{
|
||||
if (addressList.count != 0)
|
||||
{
|
||||
MTContext *context = _context;
|
||||
[context updateAddressSetForDatacenterWithId:_datacenterId addressSet:[[MTDatacenterAddressSet alloc] initWithAddressList:addressList] forceUpdateSchemes:false];
|
||||
[self complete];
|
||||
}
|
||||
else
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)getConfigFailed
|
||||
{
|
||||
[self cleanup];
|
||||
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[_mtProto stop];
|
||||
_mtProto = nil;
|
||||
}
|
||||
|
||||
- (void)cancel
|
||||
{
|
||||
[self cleanup];
|
||||
[self fail];
|
||||
}
|
||||
|
||||
- (void)complete
|
||||
{
|
||||
id<MTDiscoverDatacenterAddressActionDelegate> delegate = _delegate;
|
||||
if ([delegate respondsToSelector:@selector(discoverDatacenterAddressActionCompleted:)])
|
||||
[delegate discoverDatacenterAddressActionCompleted:self];
|
||||
}
|
||||
|
||||
- (void)fail
|
||||
{
|
||||
id<MTDiscoverDatacenterAddressActionDelegate> delegate = _delegate;
|
||||
if ([delegate respondsToSelector:@selector(discoverDatacenterAddressActionCompleted:)])
|
||||
[delegate discoverDatacenterAddressActionCompleted:self];
|
||||
}
|
||||
|
||||
@end
|
13
submodules/MtProtoKit/MTProtoKit/MTDropResponseContext.h
Normal file
13
submodules/MtProtoKit/MTProtoKit/MTDropResponseContext.h
Normal file
@ -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
|
17
submodules/MtProtoKit/MTProtoKit/MTDropResponseContext.m
Normal file
17
submodules/MtProtoKit/MTProtoKit/MTDropResponseContext.m
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
#import "MTDropResponseContext.h"
|
||||
|
||||
@implementation MTDropResponseContext
|
||||
|
||||
- (instancetype)initWithDropMessageId:(int64_t)dropMessageId
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_dropMessageId = dropMessageId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
24
submodules/MtProtoKit/MTProtoKit/MTDropRpcResultMessage.h
Normal file
24
submodules/MtProtoKit/MTProtoKit/MTDropRpcResultMessage.h
Normal file
@ -0,0 +1,24 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTDropRpcResultMessage : NSObject
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface MTDropRpcResultUnknownMessage : MTDropRpcResultMessage
|
||||
|
||||
@end
|
||||
|
||||
@interface MTDropRpcResultDroppedRunningMessage : MTDropRpcResultMessage
|
||||
|
||||
@end
|
||||
|
||||
@interface MTDropRpcResultDroppedMessage : MTDropRpcResultMessage
|
||||
|
||||
@property (nonatomic, readonly) int64_t messageId;
|
||||
@property (nonatomic, readonly) int32_t seqNo;
|
||||
@property (nonatomic, readonly) int32_t size;
|
||||
|
||||
- (instancetype)initWithMessageId:(int64_t)messageId seqNo:(int32_t)seqNo size:(int32_t)size;
|
||||
|
||||
@end
|
29
submodules/MtProtoKit/MTProtoKit/MTDropRpcResultMessage.m
Normal file
29
submodules/MtProtoKit/MTProtoKit/MTDropRpcResultMessage.m
Normal file
@ -0,0 +1,29 @@
|
||||
#import "MTDropRpcResultMessage.h"
|
||||
|
||||
@implementation MTDropRpcResultMessage
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDropRpcResultUnknownMessage
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDropRpcResultDroppedRunningMessage
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTDropRpcResultDroppedMessage
|
||||
|
||||
- (instancetype)initWithMessageId:(int64_t)messageId seqNo:(int32_t)seqNo size:(int32_t)size
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_messageId = messageId;
|
||||
_seqNo = seqNo;
|
||||
_size = size;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
91
submodules/MtProtoKit/MTProtoKit/MTEncryption.h
Normal file
91
submodules/MtProtoKit/MTProtoKit/MTEncryption.h
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
|
||||
#ifndef MTEncryption_H
|
||||
#define MTEncryption_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
NSData *MTSha1(NSData *data);
|
||||
NSData *MTSubdataSha1(NSData *data, NSUInteger offset, NSUInteger length);
|
||||
|
||||
NSData *MTSha256(NSData *data);
|
||||
|
||||
void MTRawSha1(void const *inData, NSUInteger length, void *outData);
|
||||
void MTRawSha256(void const *inData, NSUInteger length, void *outData);
|
||||
|
||||
int32_t MTMurMurHash32(const void *bytes, int length);
|
||||
|
||||
void MTAesEncryptInplace(NSMutableData *data, NSData *key, NSData *iv);
|
||||
void MTAesEncryptInplaceAndModifyIv(NSMutableData *data, NSData *key, NSMutableData *iv);
|
||||
void MTAesEncryptBytesInplaceAndModifyIv(void *data, NSInteger length, NSData *key, void *iv);
|
||||
void MTAesEncryptRaw(void const *data, void *outData, NSInteger length, void const *key, void const *iv);
|
||||
void MTAesDecryptRaw(void const *data, void *outData, NSInteger length, void const *key, void const *iv);
|
||||
void MTAesDecryptInplaceAndModifyIv(NSMutableData *data, NSData *key, NSMutableData *iv);
|
||||
void MTAesDecryptBytesInplaceAndModifyIv(void *data, NSInteger length, NSData *key, void *iv);
|
||||
NSData *MTAesEncrypt(NSData *data, NSData *key, NSData *iv);
|
||||
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv);
|
||||
NSData *MTRsaEncrypt(NSString *publicKey, NSData *data);
|
||||
NSData *MTExp(NSData *base, NSData *exp, NSData *modulus);
|
||||
NSData *MTModSub(NSData *a, NSData *b, NSData *modulus);
|
||||
NSData *MTModMul(NSData *a, NSData *b, NSData *modulus);
|
||||
NSData *MTMul(NSData *a, NSData *b);
|
||||
NSData *MTAdd(NSData *a, NSData *b);
|
||||
bool MTFactorize(uint64_t what, uint64_t *resA, uint64_t *resB);
|
||||
bool MTIsZero(NSData *value);
|
||||
|
||||
NSData *MTAesCtrDecrypt(NSData *data, NSData *key, NSData *iv);
|
||||
|
||||
@protocol MTKeychain;
|
||||
bool MTCheckIsSafeG(unsigned int g);
|
||||
bool MTCheckIsSafeB(NSData *b, NSData *p);
|
||||
bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain);
|
||||
bool MTCheckIsSafeGAOrB(NSData *gAOrB, NSData *p);
|
||||
bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain);
|
||||
|
||||
@interface MTAesCtr : NSObject
|
||||
|
||||
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv decrypt:(bool)decrypt;
|
||||
- (instancetype)initWithKey:(const void *)key keyLength:(int)keyLength iv:(const void *)iv ecount:(void *)ecount num:(uint32_t)num;
|
||||
|
||||
- (uint32_t)num;
|
||||
- (void *)ecount;
|
||||
- (void)getIv:(void *)iv;
|
||||
|
||||
- (void)encryptIn:(const unsigned char *)in out:(unsigned char *)out len:(size_t)len;
|
||||
|
||||
@end
|
||||
|
||||
uint64_t MTRsaFingerprint(NSString *key);
|
||||
|
||||
NSData *MTRsaEncryptPKCS1OAEP(NSString *key, NSData *data);
|
||||
|
||||
@interface MTBackupDatacenterAddress : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int32_t datacenterId;
|
||||
@property (nonatomic, strong, readonly) NSString *ip;
|
||||
@property (nonatomic, readonly) int32_t port;
|
||||
@property (nonatomic, strong, readonly) NSData *secret;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTBackupDatacenterData : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int32_t timestamp;
|
||||
@property (nonatomic, readonly) int32_t expirationDate;
|
||||
@property (nonatomic, strong, readonly) NSArray<MTBackupDatacenterAddress *> *addressList;
|
||||
|
||||
@end
|
||||
|
||||
MTBackupDatacenterData *MTIPDataDecode(NSData *data, NSString *phoneNumber);
|
||||
|
||||
NSData * _Nullable MTPBKDF2(NSData * _Nonnull data, NSData * _Nonnull salt, int rounds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1123
submodules/MtProtoKit/MTProtoKit/MTEncryption.m
Normal file
1123
submodules/MtProtoKit/MTProtoKit/MTEncryption.m
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTExportedAuthorizationData : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSData *authorizationBytes;
|
||||
@property (nonatomic, readonly) int32_t authorizationId;
|
||||
|
||||
- (instancetype)initWithAuthorizationBytes:(NSData *)authorizationBytes authorizationId:(int32_t)authorizationId;
|
||||
|
||||
@end
|
@ -0,0 +1,16 @@
|
||||
#import "MTExportedAuthorizationData.h"
|
||||
|
||||
@implementation MTExportedAuthorizationData
|
||||
|
||||
- (instancetype)initWithAuthorizationBytes:(NSData *)authorizationBytes authorizationId:(int32_t)authorizationId
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_authorizationBytes = authorizationBytes;
|
||||
_authorizationId = authorizationId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
22
submodules/MtProtoKit/MTProtoKit/MTFileBasedKeychain.h
Normal file
22
submodules/MtProtoKit/MTProtoKit/MTFileBasedKeychain.h
Normal file
@ -0,0 +1,22 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTKeychain.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTKeychain.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTKeychain.h>
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface MTFileBasedKeychain : NSObject <MTKeychain>
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString * _Nullable)name documentsPath:(NSString *)documentsPath;
|
||||
+ (instancetype)keychainWithName:(NSString * _Nullable)name documentsPath:(NSString * _Nullable)documentsPath;
|
||||
|
||||
- (NSDictionary<NSString *, id> *)contentsForGroup:(NSString *)group;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
403
submodules/MtProtoKit/MTProtoKit/MTFileBasedKeychain.m
Normal file
403
submodules/MtProtoKit/MTProtoKit/MTFileBasedKeychain.m
Normal file
@ -0,0 +1,403 @@
|
||||
#import "MTFileBasedKeychain.h"
|
||||
|
||||
#import "MTLogging.h"
|
||||
|
||||
#import <pthread.h>
|
||||
|
||||
#define TG_SYNCHRONIZED_DEFINE(lock) pthread_mutex_t _TG_SYNCHRONIZED_##lock
|
||||
#define TG_SYNCHRONIZED_INIT(lock) pthread_mutex_init(&_TG_SYNCHRONIZED_##lock, NULL)
|
||||
#define TG_SYNCHRONIZED_BEGIN(lock) pthread_mutex_lock(&_TG_SYNCHRONIZED_##lock);
|
||||
#define TG_SYNCHRONIZED_END(lock) pthread_mutex_unlock(&_TG_SYNCHRONIZED_##lock);
|
||||
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
#import "MTEncryption.h"
|
||||
|
||||
static TG_SYNCHRONIZED_DEFINE(_keychains) = PTHREAD_MUTEX_INITIALIZER;
|
||||
static NSMutableDictionary *keychains()
|
||||
{
|
||||
static NSMutableDictionary *dict = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
TG_SYNCHRONIZED_INIT(_keychains);
|
||||
dict = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
@interface MTFileBasedKeychain ()
|
||||
{
|
||||
NSString *_name;
|
||||
bool _encrypted;
|
||||
NSData *_aesKey;
|
||||
NSData *_aesIv;
|
||||
NSString *_documentsPath;
|
||||
|
||||
TG_SYNCHRONIZED_DEFINE(_dictByGroup);
|
||||
NSMutableDictionary *_dictByGroup;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTFileBasedKeychain
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath
|
||||
{
|
||||
if (name == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_keychains);
|
||||
MTFileBasedKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTFileBasedKeychain alloc] initWithName:name documentsPath:documentsPath encrypted:false];
|
||||
[keychains() setObject:keychain forKey:name];
|
||||
}
|
||||
TG_SYNCHRONIZED_END(_keychains);
|
||||
|
||||
return keychain;
|
||||
}
|
||||
|
||||
+ (instancetype)keychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath
|
||||
{
|
||||
if (name == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_keychains);
|
||||
MTFileBasedKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTFileBasedKeychain alloc] initWithName:name documentsPath:documentsPath encrypted:true];
|
||||
[keychains() setObject:keychain forKey:name];
|
||||
}
|
||||
TG_SYNCHRONIZED_END(_keychains);
|
||||
|
||||
return keychain;
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString *)name documentsPath:(NSString *)documentsPath encrypted:(bool)encrypted
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
TG_SYNCHRONIZED_INIT(_dictByGroup);
|
||||
_dictByGroup = [[NSMutableDictionary alloc] init];
|
||||
|
||||
_name = name;
|
||||
_documentsPath = documentsPath;
|
||||
_encrypted = encrypted;
|
||||
|
||||
if (name != nil)
|
||||
{
|
||||
if (_encrypted)
|
||||
{
|
||||
NSMutableDictionary *keychainReadQuery = [[NSMutableDictionary alloc] initWithDictionary:@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
|
||||
#endif
|
||||
(__bridge id)kSecReturnData: (id)kCFBooleanTrue,
|
||||
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
|
||||
}];
|
||||
|
||||
bool upgradeEncryption = false;
|
||||
|
||||
CFDataRef keyData = NULL;
|
||||
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainReadQuery, (CFTypeRef *)&keyData) == noErr && keyData != NULL)
|
||||
{
|
||||
NSData *data = (__bridge_transfer NSData *)keyData;
|
||||
if (data.length == 64)
|
||||
{
|
||||
_aesKey = [data subdataWithRange:NSMakeRange(0, 32)];
|
||||
_aesIv = [data subdataWithRange:NSMakeRange(32, 32)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
keychainReadQuery[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
|
||||
if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainReadQuery, (CFTypeRef *)&keyData) == noErr && keyData != NULL)
|
||||
{
|
||||
NSData *data = (__bridge_transfer NSData *)keyData;
|
||||
if (data.length == 64)
|
||||
{
|
||||
upgradeEncryption = true;
|
||||
|
||||
_aesKey = [data subdataWithRange:NSMakeRange(0, 32)];
|
||||
_aesIv = [data subdataWithRange:NSMakeRange(32, 32)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool storeKey = upgradeEncryption || _aesKey == nil || _aesIv == nil;
|
||||
|
||||
if (_aesKey == nil || _aesIv == nil)
|
||||
{
|
||||
uint8_t buf[32];
|
||||
|
||||
int result = 0;
|
||||
result = SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesKey = [[NSData alloc] initWithBytes:buf length:32];
|
||||
|
||||
result = SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesIv = [[NSData alloc] initWithBytes:buf length:32];
|
||||
}
|
||||
|
||||
NSMutableData *newKeyData = [[NSMutableData alloc] init];
|
||||
[newKeyData appendData:_aesKey];
|
||||
[newKeyData appendData:_aesIv];
|
||||
|
||||
if (storeKey)
|
||||
{
|
||||
SecItemDelete((__bridge CFDictionaryRef)@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: upgradeEncryption ? (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly : (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly
|
||||
#endif
|
||||
});
|
||||
|
||||
SecItemAdd((__bridge CFDictionaryRef)@{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrService: @"org.mtproto.MTKeychain",
|
||||
(__bridge id)kSecAttrAccount: [[NSString alloc] initWithFormat:@"MTKeychain:%@", name],
|
||||
#if TARGET_OS_IPHONE
|
||||
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly,
|
||||
#endif
|
||||
(__bridge id)kSecValueData: newKeyData
|
||||
}, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)filePathForName:(NSString *)name group:(NSString *)group
|
||||
{
|
||||
static NSString *dataDirectory = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
dataDirectory = [_documentsPath stringByAppendingPathComponent:@"mtkeychain"];
|
||||
#elif TARGET_OS_MAC
|
||||
NSString *applicationSupportPath = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
|
||||
NSString *applicationName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
dataDirectory = [[applicationSupportPath stringByAppendingPathComponent:applicationName] stringByAppendingPathComponent:@"mtkeychain"];
|
||||
#else
|
||||
# error "Unsupported OS"
|
||||
#endif
|
||||
|
||||
__autoreleasing NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:dataDirectory withIntermediateDirectories:true attributes:nil error:&error];
|
||||
if (error != nil) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error creating keychain directory: %@]", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return [dataDirectory stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"%@_%@.bin", name, group]];
|
||||
}
|
||||
|
||||
- (void)_loadKeychainIfNeeded:(NSString *)group
|
||||
{
|
||||
if (_dictByGroup[group] == nil)
|
||||
{
|
||||
if (_name != nil)
|
||||
{
|
||||
NSData *data = [[NSData alloc] initWithContentsOfFile:[self filePathForName:_name group:group]];
|
||||
if (data != nil && data.length >= 4)
|
||||
{
|
||||
uint32_t length = 0;
|
||||
[data getBytes:&length range:NSMakeRange(0, 4)];
|
||||
|
||||
uint32_t paddedLength = length;
|
||||
while (paddedLength % 16 != 0)
|
||||
{
|
||||
paddedLength++;
|
||||
}
|
||||
|
||||
if (data.length == 4 + paddedLength || data.length == 4 + paddedLength + 4)
|
||||
{
|
||||
NSMutableData *encryptedData = [[NSMutableData alloc] init];
|
||||
[encryptedData appendData:[data subdataWithRange:NSMakeRange(4, paddedLength)]];
|
||||
|
||||
NSMutableData *decryptedData = nil;
|
||||
if (_encrypted) {
|
||||
decryptedData = [[NSMutableData alloc] initWithData:MTAesDecrypt(encryptedData, _aesKey, _aesIv)];
|
||||
} else {
|
||||
decryptedData = encryptedData;
|
||||
}
|
||||
|
||||
[decryptedData setLength:length];
|
||||
|
||||
bool hashVerified = true;
|
||||
|
||||
if (data.length == 4 + paddedLength + 4)
|
||||
{
|
||||
int32_t hash = 0;
|
||||
[data getBytes:&hash range:NSMakeRange(4 + paddedLength, 4)];
|
||||
|
||||
int32_t decryptedHash = MTMurMurHash32(decryptedData.bytes, (int)decryptedData.length);
|
||||
if (hash != decryptedHash)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain invalid decrypted hash]");
|
||||
}
|
||||
hashVerified = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hashVerified)
|
||||
{
|
||||
@try
|
||||
{
|
||||
id object = [NSKeyedUnarchiver unarchiveObjectWithData:decryptedData];
|
||||
if ([object respondsToSelector:@selector(objectForKey:)] && [object respondsToSelector:@selector(setObject:forKey:)])
|
||||
_dictByGroup[group] = object;
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain invalid root object %@]", object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error parsing keychain: %@]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error loading keychain: expected data length %d, got %d]", 4 + (int)paddedLength, (int)data.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_dictByGroup[group] == nil)
|
||||
_dictByGroup[group] = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_storeKeychain:(NSString *)group
|
||||
{
|
||||
if (_dictByGroup[group] != nil && _name != nil)
|
||||
{
|
||||
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:_dictByGroup[group]];
|
||||
if (data != nil)
|
||||
{
|
||||
NSMutableData *encryptedData = [[NSMutableData alloc] initWithData:data];
|
||||
int32_t hash = MTMurMurHash32(encryptedData.bytes, (int)encryptedData.length);
|
||||
|
||||
while (encryptedData.length % 16 != 0)
|
||||
{
|
||||
uint8_t random = 0;
|
||||
arc4random_buf(&random, 1);
|
||||
[encryptedData appendBytes:&random length:1];
|
||||
}
|
||||
|
||||
if (_encrypted)
|
||||
MTAesEncryptInplace(encryptedData, _aesKey, _aesIv);
|
||||
|
||||
uint32_t length = (uint32_t)data.length;
|
||||
[encryptedData replaceBytesInRange:NSMakeRange(0, 0) withBytes:&length length:4];
|
||||
[encryptedData appendBytes:&hash length:4];
|
||||
|
||||
NSString *filePath = [self filePathForName:_name group:group];
|
||||
if (![encryptedData writeToFile:filePath atomically:true]) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error writing keychain to file]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
__autoreleasing NSError *error = nil;
|
||||
[[NSURL fileURLWithPath:filePath] setResourceValue:[NSNumber numberWithBool:true] forKey:NSURLIsExcludedFromBackupKey error:&error];
|
||||
if (error != nil) {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error setting \"exclude from backup\" flag]");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTKeychain error serializing keychain]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setObject:(id)object forKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (object == nil || aKey == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
_dictByGroup[group][aKey] = object;
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (aKey == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
id result = _dictByGroup[group][aKey];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(id<NSCopying>)aKey group:(NSString *)group
|
||||
{
|
||||
if (aKey == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
|
||||
[_dictByGroup[group] removeObjectForKey:aKey];
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (void)dropGroup:(NSString *)group
|
||||
{
|
||||
if (group == nil)
|
||||
return;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
_dictByGroup[group] = [[NSMutableDictionary alloc] init];
|
||||
[self _storeKeychain:group];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
}
|
||||
|
||||
- (NSDictionary<NSString *, id> *)contentsForGroup:(NSString *)group {
|
||||
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
|
||||
TG_SYNCHRONIZED_BEGIN(_dictByGroup);
|
||||
[self _loadKeychainIfNeeded:group];
|
||||
[_dictByGroup[group] enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, __unused BOOL * _Nonnull stop) {
|
||||
result[key] = obj;
|
||||
}];
|
||||
TG_SYNCHRONIZED_END(_dictByGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
21
submodules/MtProtoKit/MTProtoKit/MTFutureSaltsMessage.h
Normal file
21
submodules/MtProtoKit/MTProtoKit/MTFutureSaltsMessage.h
Normal file
@ -0,0 +1,21 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTFutureSalt : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int32_t validSince;
|
||||
@property (nonatomic, readonly) int32_t validUntil;
|
||||
@property (nonatomic, readonly) int64_t salt;
|
||||
|
||||
- (instancetype)initWithValidSince:(int32_t)validSince validUntil:(int32_t)validUntil salt:(int64_t)salt;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTFutureSaltsMessage : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int64_t requestMessageId;
|
||||
@property (nonatomic, readonly) int32_t now;
|
||||
@property (nonatomic, strong, readonly) NSArray *salts;
|
||||
|
||||
- (instancetype)initWithRequestMessageId:(int64_t)requestMessageId now:(int32_t)now salts:(NSArray *)salts;
|
||||
|
||||
@end
|
33
submodules/MtProtoKit/MTProtoKit/MTFutureSaltsMessage.m
Normal file
33
submodules/MtProtoKit/MTProtoKit/MTFutureSaltsMessage.m
Normal file
@ -0,0 +1,33 @@
|
||||
#import "MTFutureSaltsMessage.h"
|
||||
|
||||
@implementation MTFutureSalt
|
||||
|
||||
- (instancetype)initWithValidSince:(int32_t)validSince validUntil:(int32_t)validUntil salt:(int64_t)salt
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_validSince = validSince;
|
||||
_validUntil = validUntil;
|
||||
_salt = salt;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTFutureSaltsMessage
|
||||
|
||||
- (instancetype)initWithRequestMessageId:(int64_t)requestMessageId now:(int32_t)now salts:(NSArray *)salts
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_requestMessageId = requestMessageId;
|
||||
_now = now;
|
||||
_salts = salts;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
10
submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.h
Normal file
10
submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.h
Normal file
@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class MTSignal;
|
||||
|
||||
@interface MTHttpRequestOperation : NSObject
|
||||
|
||||
+ (MTSignal *)dataForHttpUrl:(NSURL *)url;
|
||||
+ (MTSignal *)dataForHttpUrl:(NSURL *)url headers:(NSDictionary *)headers;
|
||||
|
||||
@end
|
53
submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m
Normal file
53
submodules/MtProtoKit/MTProtoKit/MTHttpRequestOperation.m
Normal file
@ -0,0 +1,53 @@
|
||||
#import "MTHttpRequestOperation.h"
|
||||
|
||||
#import "../thirdparty/AFNetworking/AFHTTPRequestOperation.h"
|
||||
|
||||
#if defined(MtProtoKitDynamicFramework)
|
||||
# import <MTProtoKitDynamic/MTDisposable.h>
|
||||
# import <MTProtoKitDynamic/MTSignal.h>
|
||||
#elif defined(MtProtoKitMacFramework)
|
||||
# import <MTProtoKitMac/MTDisposable.h>
|
||||
# import <MTProtoKitMac/MTSignal.h>
|
||||
#else
|
||||
# import <MtProtoKit/MTDisposable.h>
|
||||
# import <MtProtoKit/MTSignal.h>
|
||||
#endif
|
||||
|
||||
@implementation MTHttpRequestOperation
|
||||
|
||||
+ (MTSignal *)dataForHttpUrl:(NSURL *)url {
|
||||
return [self dataForHttpUrl:url headers:nil];
|
||||
}
|
||||
|
||||
+ (MTSignal *)dataForHttpUrl:(NSURL *)url headers:(NSDictionary *)headers {
|
||||
return [[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) {
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
||||
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, __unused BOOL *stop) {
|
||||
[request setValue:value forHTTPHeaderField:key];
|
||||
}];
|
||||
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
|
||||
|
||||
[operation setSuccessCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
|
||||
[operation setFailureCallbackQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
|
||||
|
||||
[operation setCompletionBlockWithSuccess:^(__unused NSOperation *operation, __unused id responseObject)
|
||||
{
|
||||
[subscriber putNext:[(AFHTTPRequestOperation *)operation responseData]];
|
||||
[subscriber putCompletion];
|
||||
} failure:^(__unused NSOperation *operation, __unused NSError *error)
|
||||
{
|
||||
[subscriber putError:nil];
|
||||
}];
|
||||
|
||||
[operation start];
|
||||
|
||||
__weak AFHTTPRequestOperation *weakOperation = operation;
|
||||
|
||||
return [[MTBlockDisposable alloc] initWithBlock:^
|
||||
{
|
||||
__strong AFHTTPRequestOperation *strongOperation = weakOperation;
|
||||
[strongOperation cancel];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
@end
|
18
submodules/MtProtoKit/MTProtoKit/MTIncomingMessage.h
Normal file
18
submodules/MtProtoKit/MTProtoKit/MTIncomingMessage.h
Normal file
@ -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
|
24
submodules/MtProtoKit/MTProtoKit/MTIncomingMessage.m
Normal file
24
submodules/MtProtoKit/MTProtoKit/MTIncomingMessage.m
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
|
||||
#import "MTIncomingMessage.h"
|
||||
|
||||
@implementation MTIncomingMessage
|
||||
|
||||
- (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
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_messageId = messageId;
|
||||
_seqNo = seqNo;
|
||||
_authKeyId = authKeyId;
|
||||
_sessionId = sessionId;
|
||||
_salt = salt;
|
||||
_timestamp = timestamp;
|
||||
_size = size;
|
||||
_body = body;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
25
submodules/MtProtoKit/MTProtoKit/MTInputStream.h
Normal file
25
submodules/MtProtoKit/MTProtoKit/MTInputStream.h
Normal file
@ -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
|
429
submodules/MtProtoKit/MTProtoKit/MTInputStream.m
Normal file
429
submodules/MtProtoKit/MTProtoKit/MTInputStream.m
Normal file
@ -0,0 +1,429 @@
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "MTLogging.h"
|
||||
#import "MTInputStream.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
# import <endian.h>
|
||||
#endif
|
||||
|
||||
static inline int roundUpInput(int numToRound, int multiple)
|
||||
{
|
||||
if (multiple == 0)
|
||||
{
|
||||
return numToRound;
|
||||
}
|
||||
|
||||
int remainder = numToRound % multiple;
|
||||
if (remainder == 0)
|
||||
{
|
||||
return numToRound;
|
||||
}
|
||||
|
||||
return numToRound + multiple - remainder;
|
||||
}
|
||||
|
||||
@interface MTInputStream ()
|
||||
{
|
||||
NSInputStream *_wrappedInputStream;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTInputStream
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_wrappedInputStream = [[NSInputStream alloc] initWithData:data];
|
||||
[_wrappedInputStream open];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_wrappedInputStream close];
|
||||
}
|
||||
|
||||
- (NSInputStream *)wrappedInputStream
|
||||
{
|
||||
return _wrappedInputStream;
|
||||
}
|
||||
|
||||
- (int32_t)readInt32
|
||||
{
|
||||
int32_t value = 0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:4] != 4)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read int32");
|
||||
|
||||
@throw [[NSException alloc] initWithName:@"MTInputStreamException" reason:@"readInt32 end of stream" userInfo:@{}];
|
||||
}
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (int32_t)readInt32:(bool *)failed
|
||||
{
|
||||
int32_t value = 0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:4] != 4)
|
||||
{
|
||||
*failed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (int64_t)readInt64
|
||||
{
|
||||
int64_t value = 0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:8] != 8)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read int64");
|
||||
}
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (int64_t)readInt64:(bool *)failed
|
||||
{
|
||||
int64_t value = 0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:8] != 8)
|
||||
{
|
||||
*failed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (double)readDouble
|
||||
{
|
||||
double value = 0.0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:8] != 8)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read double");
|
||||
}
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (double)readDouble:(bool *)failed
|
||||
{
|
||||
double value = 0.0;
|
||||
|
||||
if ([_wrappedInputStream read:(uint8_t *)&value maxLength:8] != 8)
|
||||
{
|
||||
*failed = true;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
- (NSData *)readData:(int)length
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read %d bytes", length);
|
||||
}
|
||||
}
|
||||
NSData *data = [[NSData alloc] initWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSData *)readData:(int)length failed:(bool *)failed
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
free(bytes);
|
||||
*failed = true;
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [[NSData alloc] initWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSMutableData *)readMutableData:(NSUInteger)length
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read %d bytes", length);
|
||||
}
|
||||
}
|
||||
NSMutableData *data = [[NSMutableData alloc] initWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSMutableData *)readMutableData:(NSUInteger)length failed:(bool *)failed
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
free(bytes);
|
||||
*failed = true;
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *data = [[NSMutableData alloc] initWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSString *)readString
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
int paddingBytes = 0;
|
||||
|
||||
int32_t length = tmp;
|
||||
if (length == 254)
|
||||
{
|
||||
length = 0;
|
||||
[_wrappedInputStream read:((uint8_t *)&length) + 1 maxLength:3];
|
||||
length >>= 8;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
paddingBytes = roundUpInput(length, 4) - length;
|
||||
}
|
||||
else
|
||||
{
|
||||
paddingBytes = roundUpInput(length + 1, 4) - (length + 1);
|
||||
}
|
||||
|
||||
NSString *string = nil;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read %d bytes", length);
|
||||
}
|
||||
}
|
||||
|
||||
string = [[NSString alloc] initWithBytesNoCopy:bytes length:length encoding:NSUTF8StringEncoding freeWhenDone:true];
|
||||
}
|
||||
else
|
||||
{
|
||||
string = @"";
|
||||
}
|
||||
|
||||
for (int i = 0; i < paddingBytes; i++)
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)readString:(bool *)failed
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
int paddingBytes = 0;
|
||||
|
||||
int32_t length = tmp;
|
||||
if (length == 254)
|
||||
{
|
||||
length = 0;
|
||||
[_wrappedInputStream read:((uint8_t *)&length) + 1 maxLength:3];
|
||||
length >>= 8;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
paddingBytes = roundUpInput(length, 4) - length;
|
||||
}
|
||||
else
|
||||
{
|
||||
paddingBytes = roundUpInput(length + 1, 4) - (length + 1);
|
||||
}
|
||||
|
||||
NSString *string = nil;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
free(bytes);
|
||||
*failed = true;
|
||||
return nil;
|
||||
}
|
||||
|
||||
string = [[NSString alloc] initWithBytesNoCopy:bytes length:length encoding:NSUTF8StringEncoding freeWhenDone:true];
|
||||
}
|
||||
else
|
||||
{
|
||||
string = @"";
|
||||
}
|
||||
|
||||
for (int i = 0; i < paddingBytes; i++)
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSData *)readBytes
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
int paddingBytes = 0;
|
||||
|
||||
int32_t length = tmp;
|
||||
if (length == 254)
|
||||
{
|
||||
length = 0;
|
||||
[_wrappedInputStream read:((uint8_t *)&length) + 1 maxLength:3];
|
||||
length >>= 8;
|
||||
|
||||
paddingBytes = roundUpInput(length, 4) - length;
|
||||
}
|
||||
else
|
||||
{
|
||||
paddingBytes = roundUpInput(length + 1, 4) - (length + 1);
|
||||
}
|
||||
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"***** Couldn't read %d bytes", length);
|
||||
}
|
||||
}
|
||||
|
||||
NSData *result = [NSData dataWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
|
||||
for (int i = 0; i < paddingBytes; i++)
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSData *)readBytes:(bool *)failed
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
int paddingBytes = 0;
|
||||
|
||||
int32_t length = tmp;
|
||||
if (length == 254)
|
||||
{
|
||||
length = 0;
|
||||
[_wrappedInputStream read:((uint8_t *)&length) + 1 maxLength:3];
|
||||
length >>= 8;
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
# error "Big endian is not implemented"
|
||||
#else
|
||||
# error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
paddingBytes = roundUpInput(length, 4) - length;
|
||||
}
|
||||
else
|
||||
{
|
||||
paddingBytes = roundUpInput(length + 1, 4) - (length + 1);
|
||||
}
|
||||
|
||||
uint8_t *bytes = (uint8_t *)malloc(length);
|
||||
NSInteger readLen = [_wrappedInputStream read:bytes maxLength:length];
|
||||
if (readLen != length)
|
||||
{
|
||||
free(bytes);
|
||||
*failed = true;
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *result = [NSData dataWithBytesNoCopy:bytes length:length freeWhenDone:true];
|
||||
|
||||
for (int i = 0; i < paddingBytes; i++)
|
||||
[_wrappedInputStream read:&tmp maxLength:1];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
51
submodules/MtProtoKit/MTProtoKit/MTInternalId.h
Normal file
51
submodules/MtProtoKit/MTProtoKit/MTInternalId.h
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
#ifndef MtProtoKit_MTInternalId_h
|
||||
#define MtProtoKit_MTInternalId_h
|
||||
|
||||
#import <libkern/OSAtomic.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,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTInternalMessageParser : NSObject
|
||||
|
||||
+ (id)parseMessage:(NSData *)data;
|
||||
+ (id)unwrapMessage:(NSData *)data;
|
||||
|
||||
@end
|
752
submodules/MtProtoKit/MTProtoKit/MTInternalMessageParser.m
Normal file
752
submodules/MtProtoKit/MTProtoKit/MTInternalMessageParser.m
Normal file
@ -0,0 +1,752 @@
|
||||
#import "MTInternalMessageParser.h"
|
||||
|
||||
#import "MTBufferReader.h"
|
||||
|
||||
#import "MTResPqMessage.h"
|
||||
#import "MTRpcResultMessage.h"
|
||||
#import "MTRpcError.h"
|
||||
#import "MTDropRpcResultMessage.h"
|
||||
#import "MTServerDhParamsMessage.h"
|
||||
#import "MTServerDhInnerDataMessage.h"
|
||||
#import "MTSetClientDhParamsResponseMessage.h"
|
||||
#import "MTMsgsAckMessage.h"
|
||||
#import "MTMsgsStateReqMessage.h"
|
||||
#import "MTMsgsStateInfoMessage.h"
|
||||
#import "MTMsgDetailedInfoMessage.h"
|
||||
#import "MTMsgAllInfoMessage.h"
|
||||
#import "MTMessage.h"
|
||||
#import "MTMsgResendReqMessage.h"
|
||||
#import "MTBadMsgNotificationMessage.h"
|
||||
#import "MTPingMessage.h"
|
||||
#import "MTPongMessage.h"
|
||||
#import "MTNewSessionCreatedMessage.h"
|
||||
#import "MTDestroySessionResponseMessage.h"
|
||||
#import "MTMsgContainerMessage.h"
|
||||
#import "MTFutureSaltsMessage.h"
|
||||
|
||||
#import "MTLogging.h"
|
||||
|
||||
#import <zlib.h>
|
||||
|
||||
@implementation MTInternalMessageParser
|
||||
|
||||
+ (id)parseMessage:(NSData *)data
|
||||
{
|
||||
MTBufferReader *reader = [[MTBufferReader alloc] initWithData:data];
|
||||
|
||||
int32_t signature = 0;
|
||||
if ([reader readInt32:&signature])
|
||||
{
|
||||
switch (signature)
|
||||
{
|
||||
case (int32_t)0x05162463:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSData *pq = nil;
|
||||
if (![reader readTLBytes:&pq])
|
||||
return nil;
|
||||
|
||||
if (![reader readInt32:NULL])
|
||||
return nil;
|
||||
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
return nil;
|
||||
|
||||
NSMutableArray *serverPublicKeyFingerprints = [[NSMutableArray alloc] init];
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t fingerprint = 0;
|
||||
if (![reader readInt64:&fingerprint])
|
||||
return nil;
|
||||
[serverPublicKeyFingerprints addObject:@(fingerprint)];
|
||||
}
|
||||
|
||||
return [[MTResPqMessage alloc] initWithNonce:nonce serverNonce:serverNonce pq:pq serverPublicKeyFingerprints:serverPublicKeyFingerprints];
|
||||
}
|
||||
case (int32_t)0x79cb045d:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *nextNonceHash = [[NSMutableData alloc] init];
|
||||
[nextNonceHash setLength:16];
|
||||
if (![reader readBytes:nextNonceHash.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
return [[MTServerDhParamsFailMessage alloc] initWithNonce:nonce serverNonce:serverNonce nextNonceHash:nextNonceHash];
|
||||
}
|
||||
case (int32_t)0xd0e8075c:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSData *encryptedResponse = nil;
|
||||
if (![reader readTLBytes:&encryptedResponse])
|
||||
return nil;
|
||||
|
||||
return [[MTServerDhParamsOkMessage alloc] initWithNonce:nonce serverNonce:serverNonce encryptedResponse:encryptedResponse];
|
||||
}
|
||||
case (int32_t)0xb5890dba:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
int32_t g = 0;
|
||||
if (![reader readInt32:&g])
|
||||
return nil;
|
||||
|
||||
NSData *dhPrime = nil;
|
||||
if (![reader readTLBytes:&dhPrime])
|
||||
return nil;
|
||||
|
||||
NSData *gA = nil;
|
||||
if (![reader readTLBytes:&gA])
|
||||
return nil;
|
||||
|
||||
int32_t serverTime = 0;
|
||||
if (![reader readInt32:&serverTime])
|
||||
return nil;
|
||||
|
||||
return [[MTServerDhInnerDataMessage alloc] initWithNonce:nonce serverNonce:serverNonce g:g dhPrime:dhPrime gA:gA serverTime:serverTime];
|
||||
}
|
||||
case (int32_t)0x3bcbf734:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *nextNonceHash1 = [[NSMutableData alloc] init];
|
||||
[nextNonceHash1 setLength:16];
|
||||
if (![reader readBytes:nextNonceHash1.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
return [[MTSetClientDhParamsResponseOkMessage alloc] initWithNonce:nonce serverNonce:serverNonce nextNonceHash1:nextNonceHash1];
|
||||
}
|
||||
case (int32_t)0x46dc1fb9:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *nextNonceHash2 = [[NSMutableData alloc] init];
|
||||
[nextNonceHash2 setLength:16];
|
||||
if (![reader readBytes:nextNonceHash2.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
return [[MTSetClientDhParamsResponseRetryMessage alloc] initWithNonce:nonce serverNonce:serverNonce nextNonceHash2:nextNonceHash2];
|
||||
}
|
||||
case (int32_t)0xa69dae02:
|
||||
{
|
||||
NSMutableData *nonce = [[NSMutableData alloc] init];
|
||||
[nonce setLength:16];
|
||||
if (![reader readBytes:nonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *serverNonce = [[NSMutableData alloc] init];
|
||||
[serverNonce setLength:16];
|
||||
if (![reader readBytes:serverNonce.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
NSMutableData *nextNonceHash3 = [[NSMutableData alloc] init];
|
||||
[nextNonceHash3 setLength:16];
|
||||
if (![reader readBytes:nextNonceHash3.mutableBytes length:16])
|
||||
return nil;
|
||||
|
||||
return [[MTSetClientDhParamsResponseFailMessage alloc] initWithNonce:nonce serverNonce:serverNonce nextNonceHash3:nextNonceHash3];
|
||||
}
|
||||
case (int32_t)0xf35c6d01:
|
||||
{
|
||||
int64_t requestMessageId = 0;
|
||||
if (![reader readInt64:&requestMessageId])
|
||||
return nil;
|
||||
|
||||
NSData *responseData = [reader readRest];
|
||||
|
||||
return [[MTRpcResultMessage alloc] initWithRequestMessageId:requestMessageId data:responseData];
|
||||
}
|
||||
case (int32_t)0x2144ca19:
|
||||
{
|
||||
int32_t errorCode = 0;
|
||||
if (![reader readInt32:&errorCode])
|
||||
return nil;
|
||||
|
||||
NSString *errorDescription = @"";
|
||||
if (![reader readTLString:&errorDescription])
|
||||
return nil;
|
||||
|
||||
return [[MTRpcError alloc] initWithErrorCode:errorCode errorDescription:errorDescription];
|
||||
}
|
||||
case (int32_t)0x5e2ad36e:
|
||||
{
|
||||
return [[MTDropRpcResultUnknownMessage alloc] init];
|
||||
}
|
||||
case (int32_t)0xcd78e586:
|
||||
{
|
||||
return [[MTDropRpcResultDroppedRunningMessage alloc] init];
|
||||
}
|
||||
case (int32_t)0xa43ad8b7:
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
return nil;
|
||||
|
||||
int32_t seqNo = 0;
|
||||
if (![reader readInt32:&seqNo])
|
||||
return nil;
|
||||
|
||||
int32_t size = 0;
|
||||
if (![reader readInt32:&size])
|
||||
return nil;
|
||||
|
||||
return [[MTDropRpcResultDroppedMessage alloc] initWithMessageId:messageId seqNo:seqNo size:size];
|
||||
}
|
||||
case (int32_t)0xda69fb52:
|
||||
{
|
||||
if (![reader readInt32:NULL])
|
||||
return nil;
|
||||
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
return nil;
|
||||
|
||||
NSMutableArray *messageIds = [[NSMutableArray alloc] init];
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
return nil;
|
||||
[messageIds addObject:@(messageId)];
|
||||
}
|
||||
|
||||
return [[MTMsgsStateReqMessage alloc] initWithMessageIds:messageIds];
|
||||
}
|
||||
case (int32_t)0x04deb57d:
|
||||
{
|
||||
int64_t requestMessageId = 0;
|
||||
if (![reader readInt64:&requestMessageId])
|
||||
return nil;
|
||||
|
||||
NSData *info = nil;
|
||||
if (![reader readTLBytes:&info])
|
||||
return nil;
|
||||
|
||||
return [[MTMsgsStateInfoMessage alloc] initWithRequestMessageId:requestMessageId info:info];
|
||||
}
|
||||
case (int32_t)0x276d3ec6:
|
||||
{
|
||||
int64_t requestMessageId = 0;
|
||||
if (![reader readInt64:&requestMessageId])
|
||||
return nil;
|
||||
|
||||
int64_t responseMessageId = 0;
|
||||
if (![reader readInt64:&responseMessageId])
|
||||
return nil;
|
||||
|
||||
int32_t responseLength = 0;
|
||||
if (![reader readInt32:&responseLength])
|
||||
return nil;
|
||||
|
||||
int32_t status = 0;
|
||||
if (![reader readInt32:&status])
|
||||
return nil;
|
||||
|
||||
return [[MTMsgDetailedResponseInfoMessage alloc] initWithRequestMessageId:requestMessageId responseMessageId:responseMessageId responseLength:responseLength status:status];
|
||||
}
|
||||
case (int32_t)0x809db6df:
|
||||
{
|
||||
int64_t responseMessageId = 0;
|
||||
if (![reader readInt64:&responseMessageId])
|
||||
return nil;
|
||||
|
||||
int32_t responseLength = 0;
|
||||
if (![reader readInt32:&responseLength])
|
||||
return nil;
|
||||
|
||||
int32_t status = 0;
|
||||
if (![reader readInt32:&status])
|
||||
return nil;
|
||||
|
||||
return [[MTMsgDetailedInfoMessage alloc] initWithResponseMessageId:responseMessageId responseLength:responseLength status:status];
|
||||
}
|
||||
case (int32_t)0x8cc0d131:
|
||||
{
|
||||
if (![reader readInt32:NULL])
|
||||
return nil;
|
||||
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
return nil;
|
||||
|
||||
NSMutableArray *messageIds = [[NSMutableArray alloc] init];
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
return nil;
|
||||
[messageIds addObject:@(messageId)];
|
||||
}
|
||||
|
||||
NSData *info = nil;
|
||||
if (![reader readTLBytes:&info])
|
||||
return nil;
|
||||
|
||||
return [[MTMsgAllInfoMessage alloc] initWithMessageIds:messageIds info:info];
|
||||
}
|
||||
case (int32_t)0xe06046b2:
|
||||
{
|
||||
int32_t messageSignature = 0;
|
||||
if (![reader readInt32:&messageSignature] || messageSignature != (int32_t)0x5bb8e511)
|
||||
return nil;
|
||||
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
return nil;
|
||||
|
||||
int32_t seqNo = 0;
|
||||
if (![reader readInt32:&seqNo])
|
||||
return nil;
|
||||
|
||||
int32_t length = 0;
|
||||
if (![reader readInt32:&length])
|
||||
return nil;
|
||||
|
||||
NSData *data = [reader readRest];
|
||||
if (data.length != (NSUInteger)length)
|
||||
return nil;
|
||||
|
||||
return [[MTMessage alloc] initWithMessageId:messageId seqNo:seqNo data:data];
|
||||
}
|
||||
case (int32_t)0x7d861a08:
|
||||
{
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
return nil;
|
||||
|
||||
NSMutableArray *messageIds = [[NSMutableArray alloc] init];
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
return nil;
|
||||
[messageIds addObject:@(messageId)];
|
||||
}
|
||||
|
||||
return [[MTMsgResendReqMessage alloc] initWithMessageIds:messageIds];
|
||||
}
|
||||
case (int32_t)0xa7eff811:
|
||||
{
|
||||
int64_t badMessageId = 0;
|
||||
if (![reader readInt64:&badMessageId])
|
||||
return nil;
|
||||
|
||||
int32_t badMessageSeqNo = 0;
|
||||
if (![reader readInt32:&badMessageSeqNo])
|
||||
return nil;
|
||||
|
||||
int32_t errorCode = 0;
|
||||
if (![reader readInt32:&errorCode])
|
||||
return nil;
|
||||
|
||||
return [[MTBadMsgNotificationMessage alloc] initWithBadMessageId:badMessageId badMessageSeqNo:badMessageSeqNo errorCode:errorCode];
|
||||
}
|
||||
case (int32_t)0xedab447b:
|
||||
{
|
||||
int64_t badMessageId = 0;
|
||||
if (![reader readInt64:&badMessageId])
|
||||
return nil;
|
||||
|
||||
int32_t badMessageSeqNo = 0;
|
||||
if (![reader readInt32:&badMessageSeqNo])
|
||||
return nil;
|
||||
|
||||
int32_t errorCode = 0;
|
||||
if (![reader readInt32:&errorCode])
|
||||
return nil;
|
||||
|
||||
int64_t nextServerSalt = 0;
|
||||
if (![reader readInt64:&nextServerSalt])
|
||||
return nil;
|
||||
|
||||
return [[MTBadServerSaltNotificationMessage alloc] initWithBadMessageId:badMessageId badMessageSeqNo:badMessageSeqNo errorCode:errorCode nextServerSalt:nextServerSalt];
|
||||
}
|
||||
case (int32_t)0x62d6b459:
|
||||
{
|
||||
int32_t vectorSignature = 0;
|
||||
if (![reader readInt32:&vectorSignature])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msgs_ack can't read vectorSignature]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
else if (vectorSignature != (int32_t)0x1cb5c415)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msgs_ack invalid vectorSignature]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msgs_ack can't read count]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *messageIds = [[NSMutableArray alloc] init];
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msgs_ack can't read messageId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
[messageIds addObject:@(messageId)];
|
||||
}
|
||||
|
||||
return [[MTMsgsAckMessage alloc] initWithMessageIds:messageIds];
|
||||
}
|
||||
case (int32_t)0x7abe77ec:
|
||||
{
|
||||
int64_t pingId = 0;
|
||||
if (![reader readInt64:&pingId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: ping can't read pingId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[MTPingMessage alloc] initWithPingId:pingId];
|
||||
}
|
||||
case (int32_t)0x347773c5:
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: pong can't read messageId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int64_t pingId = 0;
|
||||
if (![reader readInt64:&pingId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: pong can't read pingId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[MTPongMessage alloc] initWithMessageId:messageId pingId:pingId];
|
||||
}
|
||||
case (int32_t)0x9ec20908:
|
||||
{
|
||||
int64_t firstMessageId = 0;
|
||||
if (![reader readInt64:&firstMessageId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: new_session_created can't read firstMessageId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int64_t uniqueId = 0;
|
||||
if (![reader readInt64:&uniqueId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: new_session_created can't read uniqueId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int64_t serverSalt = 0;
|
||||
if (![reader readInt64:&serverSalt])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: new_session_created can't read serverSalt]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[MTNewSessionCreatedMessage alloc] initWithFirstMessageId:firstMessageId uniqueId:uniqueId serverSalt:serverSalt];
|
||||
}
|
||||
case (int32_t)0xe22045fc:
|
||||
{
|
||||
int64_t sessionId = 0;
|
||||
if (![reader readInt64:&sessionId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: destroy_session_ok can't read sessionId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[MTDestroySessionResponseOkMessage alloc] initWithSessionId:sessionId];
|
||||
}
|
||||
case (int32_t)0x62d350c9:
|
||||
{
|
||||
int64_t sessionId = 0;
|
||||
if (![reader readInt64:&sessionId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: destroy_session_none can't read sessionId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[MTDestroySessionResponseNoneMessage alloc] initWithSessionId:sessionId];
|
||||
}
|
||||
case (int32_t)0xfb95abcd:
|
||||
{
|
||||
NSData *responsesData = [reader readRest];
|
||||
|
||||
return [[MTDestroySessionMultipleResponseMessage alloc] initWithResponses:responsesData];
|
||||
}
|
||||
case (int32_t)0x73f1f8dc:
|
||||
{
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container can't read count]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray *messages = [[NSMutableArray alloc] init];
|
||||
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int64_t messageId = 0;
|
||||
if (![reader readInt64:&messageId])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container can't read messageId]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int32_t seqNo = 0;
|
||||
if (![reader readInt32:&seqNo])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container can't read seqNo]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
int32_t length = 0;
|
||||
if (![reader readInt32:&length])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container can't read length]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (length < 0 || length > 16 * 1024 * 1024)
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container invalid length %d]", length);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *messageData = [[NSMutableData alloc] init];
|
||||
[messageData setLength:(NSUInteger)length];
|
||||
if (![reader readBytes:messageData.mutableBytes length:(NSUInteger)length])
|
||||
{
|
||||
if (MTLogEnabled()) {
|
||||
MTLog(@"[MTInternalMessageParser: msg_container can't read bytes]");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
[messages addObject:[[MTMessage alloc] initWithMessageId:messageId seqNo:seqNo data:messageData]];
|
||||
}
|
||||
|
||||
return [[MTMsgContainerMessage alloc] initWithMessages:messages];
|
||||
}
|
||||
case (int32_t)0xae500895:
|
||||
{
|
||||
int64_t requestMessageId = 0;
|
||||
if (![reader readInt64:&requestMessageId])
|
||||
return nil;
|
||||
|
||||
int32_t now = 0;
|
||||
if (![reader readInt32:&now])
|
||||
return nil;
|
||||
|
||||
int32_t count = 0;
|
||||
if (![reader readInt32:&count])
|
||||
return nil;
|
||||
|
||||
NSMutableArray *salts = [[NSMutableArray alloc] init];
|
||||
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
int32_t validSince = 0;
|
||||
if (![reader readInt32:&validSince])
|
||||
return nil;
|
||||
|
||||
int32_t validUntil = 0;
|
||||
if (![reader readInt32:&validUntil])
|
||||
return nil;
|
||||
|
||||
int64_t salt = 0;
|
||||
if (![reader readInt64:&salt])
|
||||
return nil;
|
||||
|
||||
[salts addObject:[[MTFutureSalt alloc] initWithValidSince:validSince validUntil:validUntil salt:salt]];
|
||||
}
|
||||
|
||||
return [[MTFutureSaltsMessage alloc] initWithRequestMessageId:requestMessageId now:now salts:salts];
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSData *)readBytes:(NSData *)data skippingLength:(NSUInteger)skipLength
|
||||
{
|
||||
NSUInteger offset = skipLength;
|
||||
|
||||
uint8_t tmp = 0;
|
||||
[data getBytes:&tmp range:NSMakeRange(offset, 1)];
|
||||
offset += 1;
|
||||
|
||||
int32_t length = tmp;
|
||||
if (length == 254)
|
||||
{
|
||||
length = 0;
|
||||
[data getBytes:((uint8_t *)&length) + 1 range:NSMakeRange(offset, 3)];
|
||||
offset += 3;
|
||||
length >>= 8;
|
||||
}
|
||||
|
||||
return [data subdataWithRange:NSMakeRange(offset, length)];
|
||||
}
|
||||
|
||||
+ (NSData *)decompressGZip:(NSData *)data
|
||||
{
|
||||
const int kMemoryChunkSize = 1024;
|
||||
|
||||
NSUInteger length = [data length];
|
||||
int windowBits = 15 + 32; //Default + gzip header instead of zlib header
|
||||
int retCode;
|
||||
unsigned char output[kMemoryChunkSize];
|
||||
uInt gotBack;
|
||||
NSMutableData *result;
|
||||
z_stream stream;
|
||||
|
||||
if ((length == 0) || (length > UINT_MAX)) //FIXME: Support 64 bit inputs
|
||||
return nil;
|
||||
|
||||
bzero(&stream, sizeof(z_stream));
|
||||
stream.avail_in = (uInt)length;
|
||||
stream.next_in = (unsigned char*)[data bytes];
|
||||
|
||||
retCode = inflateInit2(&stream, windowBits);
|
||||
if(retCode != Z_OK)
|
||||
{
|
||||
NSLog(@"%s: inflateInit2() failed with error %i", __PRETTY_FUNCTION__, retCode);
|
||||
return nil;
|
||||
}
|
||||
|
||||
result = [NSMutableData dataWithCapacity:(length * 4)];
|
||||
do
|
||||
{
|
||||
stream.avail_out = kMemoryChunkSize;
|
||||
stream.next_out = output;
|
||||
retCode = inflate(&stream, Z_NO_FLUSH);
|
||||
if ((retCode != Z_OK) && (retCode != Z_STREAM_END))
|
||||
{
|
||||
NSLog(@"%s: inflate() failed with error %i", __PRETTY_FUNCTION__, retCode);
|
||||
inflateEnd(&stream);
|
||||
return nil;
|
||||
}
|
||||
gotBack = kMemoryChunkSize - stream.avail_out;
|
||||
if (gotBack > 0)
|
||||
[result appendBytes:output length:gotBack];
|
||||
} while( retCode == Z_OK);
|
||||
inflateEnd(&stream);
|
||||
|
||||
return (retCode == Z_STREAM_END ? result : nil);
|
||||
}
|
||||
|
||||
+ (NSData *)unwrapMessage:(NSData *)data
|
||||
{
|
||||
if (data.length < 4)
|
||||
return data;
|
||||
|
||||
int32_t signature = 0;
|
||||
[data getBytes:&signature length:4];
|
||||
|
||||
if (signature == (int32_t)0x3072cfa1)
|
||||
{
|
||||
NSData *packedData = [self readBytes:data skippingLength:4];
|
||||
if (packedData != nil)
|
||||
{
|
||||
NSData *unpackedData = [self decompressGZip:packedData];
|
||||
return unpackedData;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@end
|
13
submodules/MtProtoKit/MTProtoKit/MTKeychain.h
Normal file
13
submodules/MtProtoKit/MTProtoKit/MTKeychain.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol MTKeychain <NSObject>
|
||||
|
||||
- (void)setObject:(id)object forKey:(NSString *)aKey group:(NSString *)group;
|
||||
- (id)objectForKey:(NSString *)aKey group:(NSString *)group;
|
||||
- (void)removeObjectForKey:(NSString *)aKey group:(NSString *)group;
|
||||
|
||||
- (void)dropGroup:(NSString *)group;
|
||||
|
||||
@end
|
3
submodules/MtProtoKit/MTProtoKit/MTKeychain.m
Normal file
3
submodules/MtProtoKit/MTProtoKit/MTKeychain.m
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
#import "MTKeychain.h"
|
23
submodules/MtProtoKit/MTProtoKit/MTLogging.h
Normal file
23
submodules/MtProtoKit/MTProtoKit/MTLogging.h
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
#ifndef MTLogging_H
|
||||
#define MTLogging_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool MTLogEnabled();
|
||||
void MTLog(NSString *format, ...);
|
||||
void MTShortLog(NSString *format, ...);
|
||||
void MTLogSetLoggingFunction(void (*function)(NSString *, va_list args));
|
||||
void MTLogSetShortLoggingFunction(void (*function)(NSString *, va_list args));
|
||||
void MTLogSetEnabled(bool);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
41
submodules/MtProtoKit/MTProtoKit/MTLogging.m
Normal file
41
submodules/MtProtoKit/MTProtoKit/MTLogging.m
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
#import "MTLogging.h"
|
||||
|
||||
static void (*loggingFunction)(NSString *, va_list args) = NULL;
|
||||
static void (*shortLoggingFunction)(NSString *, va_list args) = NULL;
|
||||
static bool MTLogEnabledValue = true;
|
||||
|
||||
bool MTLogEnabled() {
|
||||
return loggingFunction != NULL && MTLogEnabledValue;
|
||||
}
|
||||
|
||||
void MTLog(NSString *format, ...) {
|
||||
va_list L;
|
||||
va_start(L, format);
|
||||
if (loggingFunction != NULL) {
|
||||
loggingFunction(format, L);
|
||||
}
|
||||
va_end(L);
|
||||
}
|
||||
|
||||
void MTShortLog(NSString *format, ...) {
|
||||
va_list L;
|
||||
va_start(L, format);
|
||||
if (shortLoggingFunction != NULL) {
|
||||
shortLoggingFunction(format, L);
|
||||
}
|
||||
va_end(L);
|
||||
}
|
||||
|
||||
void MTLogSetLoggingFunction(void (*function)(NSString *, va_list args)) {
|
||||
loggingFunction = function;
|
||||
}
|
||||
|
||||
void MTLogSetShortLoggingFunction(void (*function)(NSString *, va_list args)) {
|
||||
shortLoggingFunction = function;
|
||||
}
|
||||
|
||||
void MTLogSetEnabled(bool enabled) {
|
||||
MTLogEnabledValue = enabled;
|
||||
}
|
11
submodules/MtProtoKit/MTProtoKit/MTMessage.h
Normal file
11
submodules/MtProtoKit/MTProtoKit/MTMessage.h
Normal file
@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTMessage : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int64_t messageId;
|
||||
@property (nonatomic, readonly) int32_t seqNo;
|
||||
@property (nonatomic, strong, readonly) NSData *data;
|
||||
|
||||
- (instancetype)initWithMessageId:(int64_t)messageId seqNo:(int32_t)seqNo data:(NSData *)data;
|
||||
|
||||
@end
|
17
submodules/MtProtoKit/MTProtoKit/MTMessage.m
Normal file
17
submodules/MtProtoKit/MTProtoKit/MTMessage.m
Normal file
@ -0,0 +1,17 @@
|
||||
#import "MTMessage.h"
|
||||
|
||||
@implementation MTMessage
|
||||
|
||||
- (instancetype)initWithMessageId:(int64_t)messageId seqNo:(int32_t)seqNo data:(NSData *)data
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_messageId = messageId;
|
||||
_seqNo = seqNo;
|
||||
_data = data;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
15
submodules/MtProtoKit/MTProtoKit/MTMessageEncryptionKey.h
Normal file
15
submodules/MtProtoKit/MTProtoKit/MTMessageEncryptionKey.h
Normal file
@ -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
|
123
submodules/MtProtoKit/MTProtoKit/MTMessageEncryptionKey.m
Normal file
123
submodules/MtProtoKit/MTProtoKit/MTMessageEncryptionKey.m
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
|
||||
#import "MTMessageEncryptionKey.h"
|
||||
|
||||
#import "MTEncryption.h"
|
||||
|
||||
@implementation MTMessageEncryptionKey
|
||||
|
||||
+ (instancetype)messageEncryptionKeyForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NSAssert(authKey != nil, @"authKey should not be nil");
|
||||
NSAssert(messageKey != nil, @"message key should not be nil");
|
||||
#endif
|
||||
|
||||
if (authKey == nil || authKey.length == 0 || messageKey == nil || messageKey.length == 0)
|
||||
return nil;
|
||||
|
||||
int x = toClient ? 8 : 0;
|
||||
|
||||
NSData *sha1_a = nil;
|
||||
{
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
[data appendData:messageKey];
|
||||
[data appendBytes:(((int8_t *)authKey.bytes) + x) length:32];
|
||||
sha1_a = MTSha1(data);
|
||||
}
|
||||
|
||||
NSData *sha1_b = nil;
|
||||
{
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
[data appendBytes:(((int8_t *)authKey.bytes) + 32 + x) length:16];
|
||||
[data appendData:messageKey];
|
||||
[data appendBytes:(((int8_t *)authKey.bytes) + 48 + x) length:16];
|
||||
sha1_b = MTSha1(data);
|
||||
}
|
||||
|
||||
NSData *sha1_c = nil;
|
||||
{
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
[data appendBytes:(((int8_t *)authKey.bytes) + 64 + x) length:32];
|
||||
[data appendData:messageKey];
|
||||
sha1_c = MTSha1(data);
|
||||
}
|
||||
|
||||
NSData *sha1_d = nil;
|
||||
{
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
[data appendData:messageKey];
|
||||
[data appendBytes:(((int8_t *)authKey.bytes) + 96 + x) length:32];
|
||||
sha1_d = MTSha1(data);
|
||||
}
|
||||
|
||||
NSMutableData *aesKey = [[NSMutableData alloc] init];
|
||||
[aesKey appendBytes:(((int8_t *)sha1_a.bytes)) length:8];
|
||||
[aesKey appendBytes:(((int8_t *)sha1_b.bytes) + 8) length:12];
|
||||
[aesKey appendBytes:(((int8_t *)sha1_c.bytes) + 4) length:12];
|
||||
|
||||
NSMutableData *aesIv = [[NSMutableData alloc] init];
|
||||
[aesIv appendBytes:(((int8_t *)sha1_a.bytes) + 8) length:12];
|
||||
[aesIv appendBytes:(((int8_t *)sha1_b.bytes)) length:8];
|
||||
[aesIv appendBytes:(((int8_t *)sha1_c.bytes) + 16) length:4];
|
||||
[aesIv appendBytes:(((int8_t *)sha1_d.bytes)) length:8];
|
||||
|
||||
MTMessageEncryptionKey *result = [[MTMessageEncryptionKey alloc] init];
|
||||
result->_key = [[NSData alloc] initWithData:aesKey];
|
||||
result->_iv = [[NSData alloc] initWithData:aesIv];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (instancetype)messageEncryptionKeyV2ForAuthKey:(NSData *)authKey messageKey:(NSData *)messageKey toClient:(bool)toClient {
|
||||
#ifdef DEBUG
|
||||
NSAssert(authKey != nil, @"authKey should not be nil");
|
||||
NSAssert(messageKey != nil, @"message key should not be nil");
|
||||
#endif
|
||||
|
||||
if (authKey == nil || authKey.length == 0 || messageKey == nil || messageKey.length == 0)
|
||||
return nil;
|
||||
|
||||
int xValue = toClient ? 8 : 0;
|
||||
|
||||
NSMutableData *sha256_a_data = [[NSMutableData alloc] init];
|
||||
[sha256_a_data appendData:messageKey];
|
||||
[sha256_a_data appendBytes:authKey.bytes + xValue length:36];
|
||||
|
||||
NSData *sha256_a = MTSha256(sha256_a_data);
|
||||
|
||||
NSMutableData *sha256_b_data = [[NSMutableData alloc] init];
|
||||
[sha256_b_data appendBytes:authKey.bytes + 40 + xValue length:36];
|
||||
[sha256_b_data appendData:messageKey];
|
||||
|
||||
NSData *sha256_b = MTSha256(sha256_b_data);
|
||||
|
||||
NSMutableData *aesKey = [[NSMutableData alloc] init];
|
||||
[aesKey appendBytes:sha256_a.bytes + 0 length:8];
|
||||
[aesKey appendBytes:sha256_b.bytes + 8 length:16];
|
||||
[aesKey appendBytes:sha256_a.bytes + 24 length:8];
|
||||
|
||||
NSMutableData *aesIv = [[NSMutableData alloc] init];
|
||||
[aesIv appendBytes:sha256_b.bytes + 0 length:8];
|
||||
[aesIv appendBytes:sha256_a.bytes + 8 length:16];
|
||||
[aesIv appendBytes:sha256_b.bytes + 24 length:8];
|
||||
|
||||
MTMessageEncryptionKey *result = [[MTMessageEncryptionKey alloc] init];
|
||||
result->_key = [[NSData alloc] initWithData:aesKey];
|
||||
result->_iv = [[NSData alloc] initWithData:aesIv];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (instancetype)initWithKey:(NSData *)key iv:(NSData *)iv
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_key = key;
|
||||
_iv = iv;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
41
submodules/MtProtoKit/MTProtoKit/MTMessageService.h
Normal file
41
submodules/MtProtoKit/MTProtoKit/MTMessageService.h
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class MTProto;
|
||||
@class MTIncomingMessage;
|
||||
@class MTMessageTransaction;
|
||||
@class MTApiEnvironment;
|
||||
|
||||
@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;
|
||||
- (void)mtProtoDidChangeSession:(MTProto *)mtProto;
|
||||
- (void)mtProtoServerDidChangeSession:(MTProto *)mtProto firstValidMessageId:(int64_t)firstValidMessageId otherValidMessageIds:(NSArray *)otherValidMessageIds;
|
||||
- (void)mtProto:(MTProto *)mtProto receivedMessage:(MTIncomingMessage *)message;
|
||||
- (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)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
|
22
submodules/MtProtoKit/MTProtoKit/MTMessageTransaction.h
Normal file
22
submodules/MtProtoKit/MTProtoKit/MTMessageTransaction.h
Normal file
@ -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
|
26
submodules/MtProtoKit/MTProtoKit/MTMessageTransaction.m
Normal file
26
submodules/MtProtoKit/MTProtoKit/MTMessageTransaction.m
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
#import "MTMessageTransaction.h"
|
||||
|
||||
#import "MTInternalId.h"
|
||||
|
||||
MTInternalIdClass(MTMessageTransaction)
|
||||
|
||||
@implementation MTMessageTransaction
|
||||
|
||||
- (instancetype)initWithMessagePayload:(NSArray *)messagePayload prepared:(void (^)(NSDictionary *messageInternalIdToPreparedMessage))prepared failed:(void (^)())failed completion:(void (^)(NSDictionary *messageInternalIdToTransactionId, NSDictionary *messageInternalIdToPreparedMessage, NSDictionary *messageInternalIdToQuickAckId))completion
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_internalId = [[MTInternalId(MTMessageTransaction) alloc] init];
|
||||
|
||||
_messagePayload = messagePayload;
|
||||
_completion = [completion copy];
|
||||
_prepared = [prepared copy];
|
||||
_failed = [failed copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
10
submodules/MtProtoKit/MTProtoKit/MTMsgAllInfoMessage.h
Normal file
10
submodules/MtProtoKit/MTProtoKit/MTMsgAllInfoMessage.h
Normal file
@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTMsgAllInfoMessage : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSArray *messageIds;
|
||||
@property (nonatomic, strong, readonly) NSData *info;
|
||||
|
||||
- (instancetype)initWithMessageIds:(NSArray *)messageIds info:(NSData *)info;
|
||||
|
||||
@end
|
16
submodules/MtProtoKit/MTProtoKit/MTMsgAllInfoMessage.m
Normal file
16
submodules/MtProtoKit/MTProtoKit/MTMsgAllInfoMessage.m
Normal file
@ -0,0 +1,16 @@
|
||||
#import "MTMsgAllInfoMessage.h"
|
||||
|
||||
@implementation MTMsgAllInfoMessage
|
||||
|
||||
- (instancetype)initWithMessageIds:(NSArray *)messageIds info:(NSData *)info
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_messageIds = messageIds;
|
||||
_info = info;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
9
submodules/MtProtoKit/MTProtoKit/MTMsgContainerMessage.h
Normal file
9
submodules/MtProtoKit/MTProtoKit/MTMsgContainerMessage.h
Normal file
@ -0,0 +1,9 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTMsgContainerMessage : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSArray *messages;
|
||||
|
||||
- (instancetype)initWithMessages:(NSArray *)messages;
|
||||
|
||||
@end
|
15
submodules/MtProtoKit/MTProtoKit/MTMsgContainerMessage.m
Normal file
15
submodules/MtProtoKit/MTProtoKit/MTMsgContainerMessage.m
Normal file
@ -0,0 +1,15 @@
|
||||
#import "MTMsgContainerMessage.h"
|
||||
|
||||
@implementation MTMsgContainerMessage
|
||||
|
||||
- (instancetype)initWithMessages:(NSArray *)messages
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_messages = messages;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
19
submodules/MtProtoKit/MTProtoKit/MTMsgDetailedInfoMessage.h
Normal file
19
submodules/MtProtoKit/MTProtoKit/MTMsgDetailedInfoMessage.h
Normal file
@ -0,0 +1,19 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTMsgDetailedInfoMessage : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int64_t responseMessageId;
|
||||
@property (nonatomic, readonly) int32_t responseLength;
|
||||
@property (nonatomic, readonly) int32_t status;
|
||||
|
||||
- (instancetype)initWithResponseMessageId:(int64_t)responseMessageId responseLength:(int32_t)responseLength status:(int32_t)status;
|
||||
|
||||
@end
|
||||
|
||||
@interface MTMsgDetailedResponseInfoMessage : MTMsgDetailedInfoMessage
|
||||
|
||||
@property (nonatomic, readonly) int64_t requestMessageId;
|
||||
|
||||
- (instancetype)initWithRequestMessageId:(int64_t)requestMessageId responseMessageId:(int64_t)responseMessageId responseLength:(int32_t)responseLength status:(int32_t)status;
|
||||
|
||||
@end
|
31
submodules/MtProtoKit/MTProtoKit/MTMsgDetailedInfoMessage.m
Normal file
31
submodules/MtProtoKit/MTProtoKit/MTMsgDetailedInfoMessage.m
Normal file
@ -0,0 +1,31 @@
|
||||
#import "MTMsgDetailedInfoMessage.h"
|
||||
|
||||
@implementation MTMsgDetailedInfoMessage
|
||||
|
||||
- (instancetype)initWithResponseMessageId:(int64_t)responseMessageId responseLength:(int32_t)responseLength status:(int32_t)status
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_responseMessageId = responseMessageId;
|
||||
_responseLength = responseLength;
|
||||
_status = status;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTMsgDetailedResponseInfoMessage
|
||||
|
||||
- (instancetype)initWithRequestMessageId:(int64_t)requestMessageId responseMessageId:(int64_t)responseMessageId responseLength:(int32_t)responseLength status:(int32_t)status
|
||||
{
|
||||
self = [super initWithResponseMessageId:responseMessageId responseLength:responseLength status:status];
|
||||
if (self != nil)
|
||||
{
|
||||
_requestMessageId = requestMessageId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
9
submodules/MtProtoKit/MTProtoKit/MTMsgResendReqMessage.h
Normal file
9
submodules/MtProtoKit/MTProtoKit/MTMsgResendReqMessage.h
Normal file
@ -0,0 +1,9 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTMsgResendReqMessage : NSObject
|
||||
|
||||
@property (nonatomic, strong, readonly) NSArray *messageIds;
|
||||
|
||||
- (instancetype)initWithMessageIds:(NSArray *)messageIds;
|
||||
|
||||
@end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user