diff --git a/MTBackupAddressSignals.m b/MTBackupAddressSignals.m index c8e55643d6..64181f6a78 100644 --- a/MTBackupAddressSignals.m +++ b/MTBackupAddressSignals.m @@ -2,6 +2,7 @@ #if defined(MtProtoKitDynamicFramework) # import +# import # import # import # import @@ -15,6 +16,7 @@ # import #elif defined(MtProtoKitMacFramework) # import +# import # import # import # import @@ -28,6 +30,7 @@ # import #else # import +# import # import # import # import @@ -46,7 +49,7 @@ + (MTSignal *)fetchBackupIpsGoogle:(bool)isTesting { NSDictionary *headers = @{@"Host": @"dns-telegram.appspot.com"}; - return [[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:isTesting ? @"https://google.com/test/" : @"https://google.com/"] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + return [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:isTesting ? @"https://google.com/test/" : @"https://google.com/"] headers:headers] mapToSignal:^MTSignal *(NSData *data) { NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; text = [text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]; NSData *result = [[NSData alloc] initWithBase64EncodedString:text options:NSDataBase64DecodingIgnoreUnknownCharacters]; @@ -58,13 +61,15 @@ } else { return [MTSignal complete]; }; + }] catch:^MTSignal *(__unused id error) { + return [MTSignal complete]; }]; } + (MTSignal *)fetchBackupIpsAzure:(bool)isTesting { NSDictionary *headers = @{@"Host": @"tcdnb.azureedge.net"}; - return [[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:isTesting ? @"https://software-download.microsoft.com/test/config.txt" : @"https://software-download.microsoft.com/prod/config.txt"] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + return [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:isTesting ? @"https://software-download.microsoft.com/test/config.txt" : @"https://software-download.microsoft.com/prod/config.txt"] headers:headers] mapToSignal:^MTSignal *(NSData *data) { NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; text = [text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]; NSData *result = [[NSData alloc] initWithBase64EncodedString:text options:NSDataBase64DecodingIgnoreUnknownCharacters]; @@ -76,13 +81,15 @@ } else { return [MTSignal complete]; }; + }] catch:^MTSignal *(__unused id error) { + return [MTSignal complete]; }]; } + (MTSignal *)fetchBackupIpsResolveGoogle:(bool)isTesting { NSDictionary *headers = @{@"Host": @"dns.google.com"}; - return [[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://google.com/resolve?name=%@&type=16", isTesting ? @"tap.stel.com" : @"ap.stel.com"]] headers:headers] mapToSignal:^MTSignal *(NSData *data) { + return [[[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:[NSString stringWithFormat:@"https://google.com/resolve?name=%@&type=16", isTesting ? @"tap.stel.com" : @"ap.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"]; @@ -119,6 +126,83 @@ } } return [MTSignal complete]; + }] catch:^MTSignal *(__unused id error) { + return [MTSignal complete]; + }]; +} + ++ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address datacenterId:(NSInteger)datacenterId currentContext:(MTContext *)currentContext { + MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy]; + + NSMutableDictionary *datacenterAddressOverrides = [[NSMutableDictionary alloc] init]; + + datacenterAddressOverrides[@(datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false secret:nil]; + 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]; + + if (datacenterId != 0) { + context.keychain = currentContext.keychain; + } + + MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:datacenterId usageCalculationInfo:nil]; + if (datacenterId != 0) { + mtProto.useTempAuthKeys = true; + } + 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" responseParser:responseParser]; + + __weak MTContext *weakCurrentContext = currentContext; + return [[MTSignal alloc] initWithGenerator:^id(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]; + }]; }]; } @@ -127,77 +211,17 @@ return [[[MTSignal mergeSignals:signals] take:1] mapToSignal:^MTSignal *(MTBackupDatacenterData *data) { if (data != nil && data.addressList.count != 0) { - MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy]; - - NSMutableDictionary *datacenterAddressOverrides = [[NSMutableDictionary alloc] init]; - - MTBackupDatacenterAddress *address = data.addressList[0]; - datacenterAddressOverrides[@(data.datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false secret:nil]; - 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]; - - if (data.datacenterId != 0) { - context.keychain = currentContext.keychain; + NSMutableArray *signals = [[NSMutableArray alloc] init]; + NSTimeInterval delay = 0.0; + for (MTBackupDatacenterAddress *address in data.addressList) { + MTSignal *signal = [self fetchConfigFromAddress:address datacenterId:data.datacenterId currentContext:currentContext]; + if (delay > DBL_EPSILON) { + signal = [signal delay:delay onQueue:[[MTQueue alloc] init]]; + } + [signals addObject:signal]; + delay += 5.0; } - - MTProto *mtProto = [[MTProto alloc] initWithContext:context datacenterId:data.datacenterId usageCalculationInfo:nil]; - if (data.datacenterId != 0) { - mtProto.useTempAuthKeys = true; - } - 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" responseParser:responseParser]; - - __weak MTContext *weakCurrentContext = currentContext; - return [[MTSignal alloc] initWithGenerator:^id(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 %@]", isTestingEnvironment ? @"testing" : @"production", [nDatacenterId intValue], addressSet); - } - - [strongCurrentContext updateAddressSetForDatacenterWithId:[nDatacenterId integerValue] addressSet:addressSet forceUpdateSchemes:true]; - } - }]; - } - } else { - [subscriber putCompletion]; - } - }]; - - [requestService addRequest:request]; - - id requestId = request.internalId; - return [[MTBlockDisposable alloc] initWithBlock:^{ - [requestService removeRequestByInternalId:requestId]; - [mtProto pause]; - }]; - }]; + return [[MTSignal mergeSignals:signals] take:1]; } return [MTSignal complete]; }]; diff --git a/MTProtoKit/MTContext.m b/MTProtoKit/MTContext.m index 9f9e6d8a8c..fdcddc725d 100644 --- a/MTProtoKit/MTContext.m +++ b/MTProtoKit/MTContext.m @@ -1121,13 +1121,21 @@ { [[MTContext contextQueue] dispatchOnQueue:^ { - for (NSNumber *nDatacenterId in _datacenterAuthActions) - { - if (_datacenterAuthActions[nDatacenterId] == action) - { - [_datacenterAuthActions removeObjectForKey:nDatacenterId]; - - break; + if (action.tempAuth) { + for (NSNumber *nDatacenterId in _datacenterTempAuthActions) { + if (_datacenterTempAuthActions[nDatacenterId] == action) { + [_datacenterTempAuthActions removeObjectForKey:nDatacenterId]; + + break; + } + } + } else { + for (NSNumber *nDatacenterId in _datacenterAuthActions) { + if (_datacenterAuthActions[nDatacenterId] == action) { + [_datacenterAuthActions removeObjectForKey:nDatacenterId]; + + break; + } } } }]; diff --git a/MTProtoKit/MTDatacenterAuthAction.h b/MTProtoKit/MTDatacenterAuthAction.h index 07e0b2d531..b6835b9c50 100644 --- a/MTProtoKit/MTDatacenterAuthAction.h +++ b/MTProtoKit/MTDatacenterAuthAction.h @@ -19,6 +19,7 @@ @interface MTDatacenterAuthAction : NSObject +@property (nonatomic, readonly) bool tempAuth; @property (nonatomic, weak) id delegate; - (instancetype)initWithTempAuth:(bool)tempAuth tempAuthKeyType:(MTDatacenterAuthTempKeyType)tempAuthKeyType; diff --git a/MTProtoKit/MTDatacenterAuthAction.m b/MTProtoKit/MTDatacenterAuthAction.m index 947aba6bd4..839ace863e 100644 --- a/MTProtoKit/MTDatacenterAuthAction.m +++ b/MTProtoKit/MTDatacenterAuthAction.m @@ -13,7 +13,6 @@ @interface MTDatacenterAuthAction () { - bool _tempAuth; MTDatacenterAuthTempKeyType _tempAuthKeyType; NSInteger _datacenterId; diff --git a/MTProtoKit/MTProto.m b/MTProtoKit/MTProto.m index 2059d7c9e1..5f6209a3a1 100644 --- a/MTProtoKit/MTProto.m +++ b/MTProtoKit/MTProto.m @@ -1983,33 +1983,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; } if (protocolErrorCode == -404) { - if (_cdn) { - _authInfo = nil; - [_context performBatchUpdates:^{ - [_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:nil]; - [_context authInfoForDatacenterWithIdRequired:_datacenterId isCdn:true]; - }]; - _mtState |= MTProtoStateAwaitingDatacenterAuthorization; - } else if (_useTempAuthKeys) { - MTDatacenterAuthTempKeyType tempAuthKeyType = MTDatacenterAuthTempKeyTypeMain; - if (transport.address.preferForMedia) { - tempAuthKeyType = MTDatacenterAuthTempKeyTypeMedia; - } - - MTDatacenterAuthKey *currentTempAuthKey = [_authInfo tempAuthKeyWithType:tempAuthKeyType]; - - _authInfo = [_authInfo withUpdatedTempAuthKeyWithType:tempAuthKeyType key:nil]; - _mtState |= MTProtoStateAwaitingDatacenterTempAuthKey; - - [_context performBatchUpdates:^{ - MTDatacenterAuthInfo *authInfo = [_context authInfoForDatacenterWithId:_datacenterId]; - if ([authInfo tempAuthKeyWithType:tempAuthKeyType].authKeyId == currentTempAuthKey.authKeyId) { - authInfo = [authInfo withUpdatedTempAuthKeyWithType:tempAuthKeyType key:nil]; - [_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo]; - [_context tempAuthKeyForDatacenterWithIdRequired:_datacenterId keyType:tempAuthKeyType]; - } - }]; - } + [self handleMissingKey:transport.address]; } if (currentTransport == _transport) @@ -2033,8 +2007,25 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; int64_t dataMessageId = 0; bool parseError = false; NSArray *parsedMessages = [self _parseIncomingMessages:decryptedData dataMessageId:&dataMessageId parseError:&parseError]; - if (parseError) - { + for (MTIncomingMessage *message in parsedMessages) { + if ([message.body isKindOfClass:[MTRpcResultMessage class]]) { + MTRpcResultMessage *rpcResultMessage = message.body; + id maybeInternalMessage = [MTInternalMessageParser parseMessage:rpcResultMessage.data]; + if ([maybeInternalMessage isKindOfClass:[MTRpcError class]]) { + MTRpcError *rpcError = maybeInternalMessage; + if (rpcError.errorCode == 401 && [rpcError.errorDescription isEqualToString:@"AUTH_KEY_PERM_EMPTY"]) { + if (MTLogEnabled()) { + MTLog(@"[MTProto#%p received AUTH_KEY_PERM_EMPTY]", self); + } + [self handleMissingKey:transport.address]; + [self requestSecureTransportReset]; + + return; + } + } + } + } + if (parseError) { if (MTLogEnabled()) { MTLog(@"[MTProto#%p incoming data parse error]", self); } @@ -2042,9 +2033,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; [self transportTransactionsMayHaveFailed:transport transactionIds:@[transactionId]]; [self resetSessionInfo]; - } - else - { + } else { [self transportTransactionsSucceeded:@[transactionId]]; for (MTIncomingMessage *incomingMessage in parsedMessages) @@ -2071,6 +2060,38 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; } }]; } + +- (void)handleMissingKey:(MTDatacenterAddress *)address { + NSAssert([[MTProto managerQueue] isCurrentQueue], @"invalid queue"); + + if (_cdn) { + _authInfo = nil; + [_context performBatchUpdates:^{ + [_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:nil]; + [_context authInfoForDatacenterWithIdRequired:_datacenterId isCdn:true]; + }]; + _mtState |= MTProtoStateAwaitingDatacenterAuthorization; + } else if (_useTempAuthKeys) { + MTDatacenterAuthTempKeyType tempAuthKeyType = MTDatacenterAuthTempKeyTypeMain; + if (address.preferForMedia) { + tempAuthKeyType = MTDatacenterAuthTempKeyTypeMedia; + } + + MTDatacenterAuthKey *currentTempAuthKey = [_authInfo tempAuthKeyWithType:tempAuthKeyType]; + + _authInfo = [_authInfo withUpdatedTempAuthKeyWithType:tempAuthKeyType key:nil]; + _mtState |= MTProtoStateAwaitingDatacenterTempAuthKey; + + [_context performBatchUpdates:^{ + MTDatacenterAuthInfo *authInfo = [_context authInfoForDatacenterWithId:_datacenterId]; + if ([authInfo tempAuthKeyWithType:tempAuthKeyType].authKeyId == currentTempAuthKey.authKeyId) { + authInfo = [authInfo withUpdatedTempAuthKeyWithType:tempAuthKeyType key:nil]; + [_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:authInfo]; + [_context tempAuthKeyForDatacenterWithIdRequired:_datacenterId keyType:tempAuthKeyType]; + } + }]; + } +} - (NSData *)_decryptIncomingTransportData:(NSData *)data address:(MTDatacenterAddress *)address { @@ -2544,8 +2565,12 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; MTDatacenterAuthKey *effectiveTempAuthKey = [_authInfo tempAuthKeyWithType:tempAuthKeyType]; if (effectiveTempAuthKey != nil) { _authInfo = [_authInfo withUpdatedTempAuthKeyWithType:tempAuthKeyType key:[[MTDatacenterAuthKey alloc] initWithAuthKey:effectiveTempAuthKey.authKey authKeyId:effectiveTempAuthKey.authKeyId notBound:false]]; + NSMutableDictionary *authKeyAttributes = [[NSMutableDictionary alloc] initWithDictionary:_authInfo.authKeyAttributes]; + [authKeyAttributes removeObjectForKey:@"apiInitializationHash"]; + _authInfo = [_authInfo withUpdatedAuthKeyAttributes:authKeyAttributes]; [_context updateAuthInfoForDatacenterWithId:_datacenterId authInfo:_authInfo]; } + _bindingTempAuthKeyId = 0; if ((_mtState & MTProtoStateBindingTempAuthKey) != 0) { [self setMtState:_mtState & (~MTProtoStateBindingTempAuthKey)]; [self requestTransportTransaction]; @@ -2554,6 +2579,8 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64; if (MTLogEnabled()) { MTLog(@"[MTProto#%p bindTempAuthKey error %@]", self, rpcError); } + + [self requestTransportTransaction]; } } } diff --git a/MTProtoKit/MTTcpConnection.m b/MTProtoKit/MTTcpConnection.m index 3e695ce166..df14c8e39c 100644 --- a/MTProtoKit/MTTcpConnection.m +++ b/MTProtoKit/MTTcpConnection.m @@ -29,7 +29,7 @@ #import "MTDNS.h" #import "MTSignal.h" -#define MT_TCPO25 0 +#define MT_TCPO25 1 MTInternalIdClass(MTTcpConnection) @@ -428,8 +428,8 @@ struct ctr_state { if (useEncryption) { int32_t controlVersion = 0xefefefef; memcpy(controlBytes + 56, &controlVersion, 4); - int32_t datacenterTag = _datacenterTag; - memcpy(controlBytes + 60, &datacenterTag, 4); + int16_t datacenterTag = (int16_t)_datacenterTag; + memcpy(controlBytes + 60, &datacenterTag, 2); uint8_t controlBytesReversed[64]; for (int i = 0; i < 64; i++) { @@ -452,6 +452,16 @@ struct ctr_state { } NSData *aesKeyHash = MTSha256(aesKeyData); aesKey = [aesKeyHash subdataWithRange:NSMakeRange(0, 32)]; + + NSMutableData *incomingAesKeyData = [[NSMutableData alloc] init]; + [incomingAesKeyData appendData:incomingAesKey]; + if (_mtpSecret != nil) { + [incomingAesKeyData appendData:_mtpSecret]; + } else if (_address.secret != nil) { + [incomingAesKeyData appendData:_address.secret]; + } + NSData *incomingAesKeyHash = MTSha256(incomingAesKeyData); + incomingAesKey = [incomingAesKeyHash subdataWithRange:NSMakeRange(0, 32)]; } #endif