mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-01 20:28:05 +00:00
Updated keychain
This commit is contained in:
parent
469b3931e6
commit
6252ca75f7
10
MTFileBasedKeychain.h
Normal file
10
MTFileBasedKeychain.h
Normal file
@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <MTProtoKit/MTKeychain.h>
|
||||
|
||||
@interface MTFileBasedKeychain : NSObject <MTKeychain>
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath;
|
||||
+ (instancetype)keychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath;
|
||||
|
||||
@end
|
||||
362
MTFileBasedKeychain.m
Normal file
362
MTFileBasedKeychain.m
Normal file
@ -0,0 +1,362 @@
|
||||
#import "MTFileBasedKeychain.h"
|
||||
|
||||
#import <MTProtoKit/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 <MTProtoKit/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];
|
||||
|
||||
SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesKey = [[NSData alloc] initWithBytes:buf length:32];
|
||||
|
||||
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)
|
||||
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 *decryptedData = [[NSMutableData alloc] init];
|
||||
[decryptedData appendData:[data subdataWithRange:NSMakeRange(4, paddedLength)]];
|
||||
if (_encrypted)
|
||||
MTAesDecryptInplace(decryptedData, _aesKey, _aesIv);
|
||||
[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)
|
||||
{
|
||||
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
|
||||
MTLog(@"[MTKeychain invalid root object %@]", object);
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
MTLog(@"[MTKeychain error parsing keychain: %@]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
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])
|
||||
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)
|
||||
MTLog(@"[MTKeychain error setting \"exclude from backup\" flag]");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
@end
|
||||
@ -14,7 +14,7 @@
|
||||
@protocol MTSerialization;
|
||||
@class MTContext;
|
||||
@class MTTransportScheme;
|
||||
@class MTKeychain;
|
||||
@protocol MTKeychain;
|
||||
@class MTSessionInfo;
|
||||
@class MTApiEnvironment;
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
@interface MTContext : NSObject
|
||||
|
||||
@property (nonatomic, strong) MTKeychain *keychain;
|
||||
@property (nonatomic, strong) id<MTKeychain> keychain;
|
||||
|
||||
@property (nonatomic, strong, readonly) id<MTSerialization> serialization;
|
||||
@property (nonatomic, strong, readonly) MTApiEnvironment *apiEnvironment;
|
||||
|
||||
@ -194,7 +194,7 @@
|
||||
[[MTContext contextQueue] dispatchOnQueue:block];
|
||||
}
|
||||
|
||||
- (void)setKeychain:(MTKeychain *)keychain
|
||||
- (void)setKeychain:(id<MTKeychain>)keychain
|
||||
{
|
||||
[[MTContext contextQueue] dispatchOnQueue:^
|
||||
{
|
||||
|
||||
@ -32,11 +32,11 @@ NSData *MTRsaEncrypt(NSString *publicKey, NSData *data);
|
||||
NSData *MTExp(NSData *base, NSData *exp, NSData *modulus);
|
||||
bool MTFactorize(uint64_t what, uint64_t *resA, uint64_t *resB);
|
||||
|
||||
@class MTKeychain;
|
||||
@protocol MTKeychain;
|
||||
bool MTCheckIsSafeG(unsigned int g);
|
||||
bool MTCheckIsSafePrime(NSData *numberBytes, MTKeychain *keychain);
|
||||
bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain);
|
||||
bool MTCheckIsSafeGAOrB(NSData *gAOrB, NSData *p);
|
||||
bool MTCheckMod(NSData *numberBytes, unsigned int g, MTKeychain *keychain);
|
||||
bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -401,7 +401,7 @@ static NSString *hexStringFromData(NSData *data)
|
||||
return string;
|
||||
}
|
||||
|
||||
bool MTCheckIsSafePrime(NSData *numberBytes, MTKeychain *keychain)
|
||||
bool MTCheckIsSafePrime(NSData *numberBytes, id<MTKeychain> keychain)
|
||||
{
|
||||
NSString *primeKey = [[NSString alloc] initWithFormat:@"isPrimeSafe_%@", hexStringFromData(numberBytes)];
|
||||
|
||||
@ -507,7 +507,7 @@ bool MTCheckIsSafeGAOrB(NSData *gAOrB, NSData *p)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MTCheckMod(NSData *numberBytes, unsigned int g, MTKeychain *keychain)
|
||||
bool MTCheckMod(NSData *numberBytes, unsigned int g, id<MTKeychain> keychain)
|
||||
{
|
||||
NSString *modKey = [[NSString alloc] initWithFormat:@"isPrimeModSafe_%@_%d", hexStringFromData(numberBytes), g];
|
||||
NSNumber *nCachedResult = [keychain objectForKey:modKey group:@"primes"];
|
||||
|
||||
@ -8,14 +8,11 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MTKeychain : NSObject
|
||||
@protocol MTKeychain <NSObject>
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath;
|
||||
+ (instancetype)keychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath;
|
||||
|
||||
- (void)setObject:(id)object forKey:(id<NSCopying>)aKey group:(NSString *)group;
|
||||
- (id)objectForKey:(id<NSCopying>)aKey group:(NSString *)group;
|
||||
- (void)removeObjectForKey:(id<NSCopying>)aKey group:(NSString *)group;
|
||||
- (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;
|
||||
|
||||
|
||||
@ -7,363 +7,3 @@
|
||||
*/
|
||||
|
||||
#import <MTProtoKit/MTKeychain.h>
|
||||
#import <MTProtoKit/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 <MTProtoKit/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 MTKeychain ()
|
||||
{
|
||||
NSString *_name;
|
||||
bool _encrypted;
|
||||
NSData *_aesKey;
|
||||
NSData *_aesIv;
|
||||
NSString *_documentsPath;
|
||||
|
||||
TG_SYNCHRONIZED_DEFINE(_dictByGroup);
|
||||
NSMutableDictionary *_dictByGroup;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MTKeychain
|
||||
|
||||
+ (instancetype)unencryptedKeychainWithName:(NSString *)name documentsPath:(NSString *)documentsPath
|
||||
{
|
||||
if (name == nil)
|
||||
return nil;
|
||||
|
||||
TG_SYNCHRONIZED_BEGIN(_keychains);
|
||||
MTKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTKeychain 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);
|
||||
MTKeychain *keychain = [keychains() objectForKey:name];
|
||||
if (keychain == nil)
|
||||
{
|
||||
keychain = [[MTKeychain 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];
|
||||
|
||||
SecRandomCopyBytes(kSecRandomDefault, 32, buf);
|
||||
_aesKey = [[NSData alloc] initWithBytes:buf length:32];
|
||||
|
||||
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)
|
||||
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 *decryptedData = [[NSMutableData alloc] init];
|
||||
[decryptedData appendData:[data subdataWithRange:NSMakeRange(4, paddedLength)]];
|
||||
if (_encrypted)
|
||||
MTAesDecryptInplace(decryptedData, _aesKey, _aesIv);
|
||||
[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)
|
||||
{
|
||||
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
|
||||
MTLog(@"[MTKeychain invalid root object %@]", object);
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
MTLog(@"[MTKeychain error parsing keychain: %@]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
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])
|
||||
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)
|
||||
MTLog(@"[MTKeychain error setting \"exclude from backup\" flag]");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -21,3 +21,10 @@ FOUNDATION_EXPORT const unsigned char MtProtoKitVersionString[];
|
||||
#import <MTProtoKit/MTProto.h>
|
||||
#import <MTProtoKit/MTRequestMessageService.h>
|
||||
#import <MTProtoKit/MTRequest.h>
|
||||
#import <MTProtoKit/MTKeychain.h>
|
||||
#import <MTProtoKit/MTSerialization.h>
|
||||
#import <MTProtoKit/MTDatacenterAddress.h>
|
||||
#import <MTProtoKit/MTDatacenterAddressSet.h>
|
||||
#import <MTProtoKit/MTApiEnvironment.h>
|
||||
#import <MTProtoKit/MTEncryption.h>
|
||||
#import <MTProtoKit/MTIncomingMessage.h>
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
D0580AC31B0F3E9C00E8235B /* MTDiscoverConnectionSignals.m in Sources */ = {isa = PBXBuildFile; fileRef = D0580AC11B0F3E9C00E8235B /* MTDiscoverConnectionSignals.m */; };
|
||||
D079AB9C1AF39B8000076F59 /* MtProtoKitMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D079AB9B1AF39B8000076F59 /* MtProtoKitMac.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D079ABB01AF39BA400076F59 /* MTProtoKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D063A31D18B158AE00C65116 /* MTProtoKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D09A59581B582EFF00FC3724 /* MTFileBasedKeychain.h in Headers */ = {isa = PBXBuildFile; fileRef = D09A59561B582EFF00FC3724 /* MTFileBasedKeychain.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D09A59591B582EFF00FC3724 /* MTFileBasedKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = D09A59571B582EFF00FC3724 /* MTFileBasedKeychain.m */; };
|
||||
D0CB05FC1ADC4483005E298F /* MtProtoKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D0CB05FB1ADC4483005E298F /* MtProtoKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D0CB06101ADC44B7005E298F /* MTTime.m in Sources */ = {isa = PBXBuildFile; fileRef = 93DBD23418B2DA1E00631ADC /* MTTime.m */; };
|
||||
D0CB06111ADC44B7005E298F /* MTTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D05A84D818AFE81C007F1076 /* MTTimer.m */; };
|
||||
@ -119,7 +121,7 @@
|
||||
D0D1A03D1ADD983C007D9ED6 /* MTDestroySessionResponseMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A00B1ADD983C007D9ED6 /* MTDestroySessionResponseMessage.m */; };
|
||||
D0D1A03E1ADD983C007D9ED6 /* MTDropRpcResultMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A00C1ADD983C007D9ED6 /* MTDropRpcResultMessage.h */; };
|
||||
D0D1A03F1ADD983C007D9ED6 /* MTDropRpcResultMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A00D1ADD983C007D9ED6 /* MTDropRpcResultMessage.m */; };
|
||||
D0D1A0401ADD983C007D9ED6 /* MTExportedAuthorizationData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A00E1ADD983C007D9ED6 /* MTExportedAuthorizationData.h */; };
|
||||
D0D1A0401ADD983C007D9ED6 /* MTExportedAuthorizationData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A00E1ADD983C007D9ED6 /* MTExportedAuthorizationData.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D0D1A0411ADD983C007D9ED6 /* MTExportedAuthorizationData.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A00F1ADD983C007D9ED6 /* MTExportedAuthorizationData.m */; };
|
||||
D0D1A0421ADD983C007D9ED6 /* MTFutureSaltsMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A0101ADD983C007D9ED6 /* MTFutureSaltsMessage.h */; };
|
||||
D0D1A0431ADD983C007D9ED6 /* MTFutureSaltsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A0111ADD983C007D9ED6 /* MTFutureSaltsMessage.m */; };
|
||||
@ -149,7 +151,7 @@
|
||||
D0D1A05B1ADD983C007D9ED6 /* MTPongMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A0291ADD983C007D9ED6 /* MTPongMessage.m */; };
|
||||
D0D1A05C1ADD983C007D9ED6 /* MTResPqMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A02A1ADD983C007D9ED6 /* MTResPqMessage.h */; };
|
||||
D0D1A05D1ADD983C007D9ED6 /* MTResPqMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A02B1ADD983C007D9ED6 /* MTResPqMessage.m */; };
|
||||
D0D1A05E1ADD983C007D9ED6 /* MTRpcError.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A02C1ADD983C007D9ED6 /* MTRpcError.h */; };
|
||||
D0D1A05E1ADD983C007D9ED6 /* MTRpcError.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A02C1ADD983C007D9ED6 /* MTRpcError.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D0D1A05F1ADD983C007D9ED6 /* MTRpcError.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A02D1ADD983C007D9ED6 /* MTRpcError.m */; };
|
||||
D0D1A0601ADD983C007D9ED6 /* MTRpcResultMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A02E1ADD983C007D9ED6 /* MTRpcResultMessage.h */; };
|
||||
D0D1A0611ADD983C007D9ED6 /* MTRpcResultMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A02F1ADD983C007D9ED6 /* MTRpcResultMessage.m */; };
|
||||
@ -159,11 +161,24 @@
|
||||
D0D1A0651ADD983C007D9ED6 /* MTServerDhParamsMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A0331ADD983C007D9ED6 /* MTServerDhParamsMessage.m */; };
|
||||
D0D1A0661ADD983C007D9ED6 /* MTSetClientDhParamsResponseMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A0341ADD983C007D9ED6 /* MTSetClientDhParamsResponseMessage.h */; };
|
||||
D0D1A0671ADD983C007D9ED6 /* MTSetClientDhParamsResponseMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A0351ADD983C007D9ED6 /* MTSetClientDhParamsResponseMessage.m */; };
|
||||
D0D1A06B1ADD987A007D9ED6 /* MTDatacenterAddressListData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A0691ADD987A007D9ED6 /* MTDatacenterAddressListData.h */; };
|
||||
D0D1A06B1ADD987A007D9ED6 /* MTDatacenterAddressListData.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D1A0691ADD987A007D9ED6 /* MTDatacenterAddressListData.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D0D1A06C1ADD987A007D9ED6 /* MTDatacenterAddressListData.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D1A06A1ADD987A007D9ED6 /* MTDatacenterAddressListData.m */; };
|
||||
D0D1A0721ADDE2FC007D9ED6 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D1A0711ADDE2FC007D9ED6 /* libz.dylib */; };
|
||||
D0D225101B4D817B0085E26D /* MtProtoKitDynamic.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D2250F1B4D817B0085E26D /* MtProtoKitDynamic.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D0D225161B4D817B0085E26D /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D2250B1B4D817B0085E26D /* MtProtoKitDynamic.framework */; };
|
||||
D0D2251D1B4D817B0085E26D /* MtProtoKitDynamicTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D0D2251C1B4D817B0085E26D /* MtProtoKitDynamicTests.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
D0D225171B4D817B0085E26D /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D05A830A18AFB3F9007F1076 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D0D2250A1B4D817B0085E26D;
|
||||
remoteInfo = MtProtoKitDynamic;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
93DBD22F18B2D72800631ADC /* MTRequestErrorContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTRequestErrorContext.h; path = MtProtoKit/MTRequestErrorContext.h; sourceTree = "<group>"; };
|
||||
93DBD23018B2D72800631ADC /* MTRequestErrorContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTRequestErrorContext.m; path = MtProtoKit/MTRequestErrorContext.m; sourceTree = "<group>"; };
|
||||
@ -367,6 +382,8 @@
|
||||
D079AB9B1AF39B8000076F59 /* MtProtoKitMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MtProtoKitMac.h; sourceTree = "<group>"; };
|
||||
D079ABA71AF39B8000076F59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D079ABA81AF39B8000076F59 /* MtProtoKitMacTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MtProtoKitMacTests.m; sourceTree = "<group>"; };
|
||||
D09A59561B582EFF00FC3724 /* MTFileBasedKeychain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTFileBasedKeychain.h; sourceTree = "<group>"; };
|
||||
D09A59571B582EFF00FC3724 /* MTFileBasedKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTFileBasedKeychain.m; sourceTree = "<group>"; };
|
||||
D0A44E4D18B24A6000B64FC6 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcrypto.a; sourceTree = "<group>"; };
|
||||
D0CB05F71ADC4483005E298F /* MtProtoKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MtProtoKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0CB05FA1ADC4483005E298F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@ -426,6 +443,12 @@
|
||||
D0D1A0691ADD987A007D9ED6 /* MTDatacenterAddressListData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MTDatacenterAddressListData.h; path = MTProtoKit/MTDatacenterAddressListData.h; sourceTree = "<group>"; };
|
||||
D0D1A06A1ADD987A007D9ED6 /* MTDatacenterAddressListData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MTDatacenterAddressListData.m; path = MTProtoKit/MTDatacenterAddressListData.m; sourceTree = "<group>"; };
|
||||
D0D1A0711ADDE2FC007D9ED6 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
D0D2250B1B4D817B0085E26D /* MtProtoKitDynamic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MtProtoKitDynamic.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0D2250E1B4D817B0085E26D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D0D2250F1B4D817B0085E26D /* MtProtoKitDynamic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MtProtoKitDynamic.h; sourceTree = "<group>"; };
|
||||
D0D225151B4D817B0085E26D /* MtProtoKitDynamicTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MtProtoKitDynamicTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0D2251B1B4D817B0085E26D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D0D2251C1B4D817B0085E26D /* MtProtoKitDynamicTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MtProtoKitDynamicTests.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -446,6 +469,21 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225071B4D817B0085E26D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225121B4D817B0085E26D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0D225161B4D817B0085E26D /* MtProtoKitDynamic.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@ -564,6 +602,8 @@
|
||||
D0CB06051ADC4483005E298F /* MtProtoKitTests */,
|
||||
D079AB981AF39B8000076F59 /* MtProtoKitMac */,
|
||||
D079ABA51AF39B8000076F59 /* MtProtoKitMacTests */,
|
||||
D0D2250C1B4D817B0085E26D /* MtProtoKitDynamic */,
|
||||
D0D225191B4D817B0085E26D /* MtProtoKitDynamicTests */,
|
||||
D05A831618AFB3F9007F1076 /* Frameworks */,
|
||||
D05A831518AFB3F9007F1076 /* Products */,
|
||||
);
|
||||
@ -574,6 +614,8 @@
|
||||
children = (
|
||||
D0CB05F71ADC4483005E298F /* MtProtoKit.framework */,
|
||||
D079AB971AF39B8000076F59 /* MtProtoKitMac.framework */,
|
||||
D0D2250B1B4D817B0085E26D /* MtProtoKitDynamic.framework */,
|
||||
D0D225151B4D817B0085E26D /* MtProtoKitDynamicTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -695,6 +737,8 @@
|
||||
children = (
|
||||
D05A83C018AFB75B007F1076 /* MTKeychain.h */,
|
||||
D05A83A318AFB75B007F1076 /* MTKeychain.m */,
|
||||
D09A59561B582EFF00FC3724 /* MTFileBasedKeychain.h */,
|
||||
D09A59571B582EFF00FC3724 /* MTFileBasedKeychain.m */,
|
||||
);
|
||||
name = Keychain;
|
||||
sourceTree = "<group>";
|
||||
@ -1065,6 +1109,40 @@
|
||||
name = Messages;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0D2250C1B4D817B0085E26D /* MtProtoKitDynamic */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0D2250F1B4D817B0085E26D /* MtProtoKitDynamic.h */,
|
||||
D0D2250D1B4D817B0085E26D /* Supporting Files */,
|
||||
);
|
||||
path = MtProtoKitDynamic;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0D2250D1B4D817B0085E26D /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0D2250E1B4D817B0085E26D /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0D225191B4D817B0085E26D /* MtProtoKitDynamicTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0D2251C1B4D817B0085E26D /* MtProtoKitDynamicTests.m */,
|
||||
D0D2251A1B4D817B0085E26D /* Supporting Files */,
|
||||
);
|
||||
path = MtProtoKitDynamicTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0D2251A1B4D817B0085E26D /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0D2251B1B4D817B0085E26D /* Info.plist */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@ -1132,6 +1210,7 @@
|
||||
D0D1A05E1ADD983C007D9ED6 /* MTRpcError.h in Headers */,
|
||||
D0CB063A1ADC4591005E298F /* MTTimeFixContext.h in Headers */,
|
||||
D0CB065D1ADC45CE005E298F /* MTTcpConnectionBehaviour.h in Headers */,
|
||||
D09A59581B582EFF00FC3724 /* MTFileBasedKeychain.h in Headers */,
|
||||
D0CB06311ADC4583005E298F /* MTDatacenterAddressSet.h in Headers */,
|
||||
D0D1A03C1ADD983C007D9ED6 /* MTDestroySessionResponseMessage.h in Headers */,
|
||||
D0CB061E1ADC4541005E298F /* MTOutputStream.h in Headers */,
|
||||
@ -1159,6 +1238,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225081B4D817B0085E26D /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0D225101B4D817B0085E26D /* MtProtoKitDynamic.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -1198,6 +1285,42 @@
|
||||
productReference = D0CB05F71ADC4483005E298F /* MtProtoKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
D0D2250A1B4D817B0085E26D /* MtProtoKitDynamic */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D0D225221B4D817B0085E26D /* Build configuration list for PBXNativeTarget "MtProtoKitDynamic" */;
|
||||
buildPhases = (
|
||||
D0D225061B4D817B0085E26D /* Sources */,
|
||||
D0D225071B4D817B0085E26D /* Frameworks */,
|
||||
D0D225081B4D817B0085E26D /* Headers */,
|
||||
D0D225091B4D817B0085E26D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = MtProtoKitDynamic;
|
||||
productName = MtProtoKitDynamic;
|
||||
productReference = D0D2250B1B4D817B0085E26D /* MtProtoKitDynamic.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
D0D225141B4D817B0085E26D /* MtProtoKitDynamicTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D0D225231B4D817B0085E26D /* Build configuration list for PBXNativeTarget "MtProtoKitDynamicTests" */;
|
||||
buildPhases = (
|
||||
D0D225111B4D817B0085E26D /* Sources */,
|
||||
D0D225121B4D817B0085E26D /* Frameworks */,
|
||||
D0D225131B4D817B0085E26D /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D0D225181B4D817B0085E26D /* PBXTargetDependency */,
|
||||
);
|
||||
name = MtProtoKitDynamicTests;
|
||||
productName = MtProtoKitDynamicTests;
|
||||
productReference = D0D225151B4D817B0085E26D /* MtProtoKitDynamicTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@ -1213,6 +1336,12 @@
|
||||
D0CB05F61ADC4483005E298F = {
|
||||
CreatedOnToolsVersion = 6.3;
|
||||
};
|
||||
D0D2250A1B4D817B0085E26D = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
};
|
||||
D0D225141B4D817B0085E26D = {
|
||||
CreatedOnToolsVersion = 6.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D05A830D18AFB3F9007F1076 /* Build configuration list for PBXProject "MtProtoKit" */;
|
||||
@ -1229,6 +1358,8 @@
|
||||
targets = (
|
||||
D0CB05F61ADC4483005E298F /* MtProtoKit */,
|
||||
D079AB961AF39B8000076F59 /* MtProtoKitMac */,
|
||||
D0D2250A1B4D817B0085E26D /* MtProtoKitDynamic */,
|
||||
D0D225141B4D817B0085E26D /* MtProtoKitDynamicTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@ -1248,6 +1379,20 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225091B4D817B0085E26D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225131B4D817B0085E26D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@ -1282,6 +1427,7 @@
|
||||
D0D1A0511ADD983C007D9ED6 /* MTMsgsAckMessage.m in Sources */,
|
||||
D0CB066F1ADC49FF005E298F /* AFHTTPRequestOperation.m in Sources */,
|
||||
D0D1A06C1ADD987A007D9ED6 /* MTDatacenterAddressListData.m in Sources */,
|
||||
D09A59591B582EFF00FC3724 /* MTFileBasedKeychain.m in Sources */,
|
||||
D0CB06681ADC45DA005E298F /* MTHttpWorker.m in Sources */,
|
||||
D0CB06561ADC45BA005E298F /* MTApiEnvironment.m in Sources */,
|
||||
D0D1A05F1ADD983C007D9ED6 /* MTRpcError.m in Sources */,
|
||||
@ -1340,8 +1486,31 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225061B4D817B0085E26D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D0D225111B4D817B0085E26D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0D2251D1B4D817B0085E26D /* MtProtoKitDynamicTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
D0D225181B4D817B0085E26D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D0D2250A1B4D817B0085E26D /* MtProtoKitDynamic */;
|
||||
targetProxy = D0D225171B4D817B0085E26D /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
D05A833518AFB3F9007F1076 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@ -1591,6 +1760,110 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D0D2251E1B4D817B0085E26D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D0D2251F1B4D817B0085E26D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = MtProtoKitDynamic/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D0D225201B4D817B0085E26D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = MtProtoKitDynamicTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D0D225211B4D817B0085E26D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = MtProtoKitDynamicTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.4;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@ -1621,6 +1894,24 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D0D225221B4D817B0085E26D /* Build configuration list for PBXNativeTarget "MtProtoKitDynamic" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D0D2251E1B4D817B0085E26D /* Debug */,
|
||||
D0D2251F1B4D817B0085E26D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D0D225231B4D817B0085E26D /* Build configuration list for PBXNativeTarget "MtProtoKitDynamicTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D0D225201B4D817B0085E26D /* Debug */,
|
||||
D0D225211B4D817B0085E26D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D05A830A18AFB3F9007F1076 /* Project object */;
|
||||
|
||||
26
MtProtoKitDynamic/Info.plist
Normal file
26
MtProtoKitDynamic/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>org.telegram.$(PRODUCT_NAME:rfc1034identifier)</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>
|
||||
19
MtProtoKitDynamic/MtProtoKitDynamic.h
Normal file
19
MtProtoKitDynamic/MtProtoKitDynamic.h
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// MtProtoKitDynamic.h
|
||||
// MtProtoKitDynamic
|
||||
//
|
||||
// Created by Peter on 08/07/15.
|
||||
// Copyright (c) 2015 Telegram. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for MtProtoKitDynamic.
|
||||
FOUNDATION_EXPORT double MtProtoKitDynamicVersionNumber;
|
||||
|
||||
//! Project version string for MtProtoKitDynamic.
|
||||
FOUNDATION_EXPORT const unsigned char MtProtoKitDynamicVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <MtProtoKitDynamic/PublicHeader.h>
|
||||
|
||||
|
||||
24
MtProtoKitDynamicTests/Info.plist
Normal file
24
MtProtoKitDynamicTests/Info.plist
Normal file
@ -0,0 +1,24 @@
|
||||
<?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>org.telegram.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
40
MtProtoKitDynamicTests/MtProtoKitDynamicTests.m
Normal file
40
MtProtoKitDynamicTests/MtProtoKitDynamicTests.m
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// MtProtoKitDynamicTests.m
|
||||
// MtProtoKitDynamicTests
|
||||
//
|
||||
// Created by Peter on 08/07/15.
|
||||
// Copyright (c) 2015 Telegram. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface MtProtoKitDynamicTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation MtProtoKitDynamicTests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample {
|
||||
// This is an example of a functional test case.
|
||||
XCTAssert(YES, @"Pass");
|
||||
}
|
||||
|
||||
- (void)testPerformanceExample {
|
||||
// This is an example of a performance test case.
|
||||
[self measureBlock:^{
|
||||
// Put the code you want to measure the time of here.
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
Loading…
x
Reference in New Issue
Block a user