mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-04-24 08:36:07 +02:00
1074 lines
31 KiB
Objective-C
1074 lines
31 KiB
Objective-C
#import <MtProtoKit/MTApiEnvironment.h>
|
|
|
|
#if TARGET_OS_IPHONE
|
|
#import <UIKit/UIKit.h>
|
|
#else
|
|
|
|
#endif
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#import <CommonCrypto/CommonDigest.h>
|
|
|
|
static NSData *_Nullable parseHexString(NSString *_Nonnull hex) {
|
|
if ([hex length] % 2 != 0) {
|
|
return nil;
|
|
}
|
|
char buf[3];
|
|
buf[2] = '\0';
|
|
uint8_t *bytes = (uint8_t *)malloc(hex.length / 2);
|
|
uint8_t *bp = bytes;
|
|
for (CFIndex i = 0; i < [hex length]; i += 2) {
|
|
buf[0] = [hex characterAtIndex:i];
|
|
buf[1] = [hex characterAtIndex:i + 1];
|
|
char *b2 = NULL;
|
|
*bp++ = strtol(buf, &b2, 16);
|
|
if (b2 != buf + 2) {
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
return [NSData dataWithBytesNoCopy:bytes
|
|
length:[hex length] / 2
|
|
freeWhenDone:YES];
|
|
}
|
|
|
|
static NSString *_Nonnull dataToHexString(NSData *_Nonnull data) {
|
|
const unsigned char *dataBuffer = (const unsigned char *)[data bytes];
|
|
if (dataBuffer == NULL) {
|
|
return @"";
|
|
}
|
|
|
|
NSUInteger dataLength = [data length];
|
|
NSMutableString *hexString =
|
|
[NSMutableString stringWithCapacity:(dataLength * 2)];
|
|
|
|
for (int i = 0; i < (int)dataLength; ++i) {
|
|
[hexString
|
|
appendString:[NSString stringWithFormat:@"%02lx",
|
|
(unsigned long)dataBuffer[i]]];
|
|
}
|
|
|
|
return hexString;
|
|
}
|
|
|
|
static NSData *base64_decode(NSString *str) {
|
|
if ([NSData instancesRespondToSelector:@selector
|
|
(initWithBase64EncodedString:options:)]) {
|
|
NSData *data = [[NSData alloc]
|
|
initWithBase64EncodedString:str
|
|
options:
|
|
NSDataBase64DecodingIgnoreUnknownCharacters];
|
|
return data;
|
|
} else {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
return [[NSData alloc]
|
|
initWithBase64Encoding:
|
|
[str stringByReplacingOccurrencesOfString:@"[^A-Za-z0-9+/=]"
|
|
withString:@""
|
|
options:NSRegularExpressionSearch
|
|
range:NSMakeRange(
|
|
0, [str length])]];
|
|
#pragma clang diagnostic pop
|
|
}
|
|
}
|
|
|
|
static NSDictionary<NSNumber *, NSDictionary<NSString *, NSString *> *> *
|
|
MTDeviceSpoofProfiles(void) {
|
|
static NSDictionary<NSNumber *, NSDictionary<NSString *, NSString *> *>
|
|
*profiles;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
profiles = @{
|
|
@1 : @{
|
|
@"deviceModel" : @"iPhone 14 Pro",
|
|
@"systemVersion" : @"iOS 17.2"
|
|
},
|
|
@2 : @{
|
|
@"deviceModel" : @"iPhone 15 Pro Max",
|
|
@"systemVersion" : @"iOS 17.4"
|
|
},
|
|
@3 : @{
|
|
@"deviceModel" : @"Samsung SM-S918B",
|
|
@"systemVersion" : @"Android 14"
|
|
},
|
|
@4 : @{
|
|
@"deviceModel" : @"Google Pixel 8 Pro",
|
|
@"systemVersion" : @"Android 14"
|
|
},
|
|
@5 : @{
|
|
@"deviceModel" : @"PC 64bit",
|
|
@"systemVersion" : @"Windows 11"
|
|
},
|
|
@6 : @{
|
|
@"deviceModel" : @"MacBook Pro",
|
|
@"systemVersion" : @"macOS 14.3"
|
|
},
|
|
@7 : @{
|
|
@"deviceModel" : @"Web",
|
|
@"systemVersion" : @"Chrome 121"
|
|
},
|
|
@8 : @{
|
|
@"deviceModel" : @"HUAWEI MNA-LX9",
|
|
@"systemVersion" : @"HarmonyOS 4.0"
|
|
},
|
|
@9 : @{
|
|
@"deviceModel" : @"Xiaomi 2311DRK48G",
|
|
@"systemVersion" : @"Android 14"
|
|
}
|
|
};
|
|
});
|
|
return profiles;
|
|
}
|
|
|
|
static NSString *MTDeviceSpoofTrimmedString(NSString *value) {
|
|
if (value == nil) {
|
|
return @"";
|
|
}
|
|
return
|
|
[value stringByTrimmingCharactersInSet:
|
|
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
}
|
|
|
|
static NSInteger MTDeviceSpoofSanitizedProfileId(NSUserDefaults *defaults) {
|
|
NSInteger profileId =
|
|
[defaults integerForKey:@"DeviceSpoof.selectedProfileId"];
|
|
if (profileId == 0 || profileId == 100 ||
|
|
MTDeviceSpoofProfiles()[@(profileId)] != nil) {
|
|
return profileId;
|
|
}
|
|
[defaults setInteger:0 forKey:@"DeviceSpoof.selectedProfileId"];
|
|
return 0;
|
|
}
|
|
|
|
static BOOL MTDeviceSpoofIsEnabled(NSUserDefaults *defaults) {
|
|
return [defaults boolForKey:@"DeviceSpoof.hasExplicitConfiguration"] &&
|
|
[defaults boolForKey:@"DeviceSpoof.isEnabled"];
|
|
}
|
|
|
|
static void MTDeviceSpoofResolveValues(NSUserDefaults *defaults,
|
|
NSString *__autoreleasing *deviceModel,
|
|
NSString *__autoreleasing *systemVersion) {
|
|
*deviceModel = nil;
|
|
*systemVersion = nil;
|
|
|
|
if (!MTDeviceSpoofIsEnabled(defaults)) {
|
|
return;
|
|
}
|
|
|
|
NSInteger profileId = MTDeviceSpoofSanitizedProfileId(defaults);
|
|
if (profileId == 0) {
|
|
return;
|
|
}
|
|
|
|
if (profileId == 100) {
|
|
NSString *customDeviceModel =
|
|
MTDeviceSpoofTrimmedString([defaults stringForKey:@"DeviceSpoof.customDeviceModel"]);
|
|
NSString *customSystemVersion =
|
|
MTDeviceSpoofTrimmedString([defaults stringForKey:@"DeviceSpoof.customSystemVersion"]);
|
|
if (customDeviceModel.length == 0 || customSystemVersion.length == 0) {
|
|
return;
|
|
}
|
|
*deviceModel = customDeviceModel;
|
|
*systemVersion = customSystemVersion;
|
|
return;
|
|
}
|
|
|
|
NSDictionary<NSString *, NSString *> *profile =
|
|
MTDeviceSpoofProfiles()[@(profileId)];
|
|
*deviceModel = profile[@"deviceModel"];
|
|
*systemVersion = profile[@"systemVersion"];
|
|
}
|
|
|
|
@implementation MTProxySecret
|
|
|
|
- (instancetype _Nullable)initWithSecret:(NSData *_Nonnull)secret {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_secret = secret;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_secret = [aDecoder decodeObjectForKey:@"secret"];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
|
[aCoder encodeObject:_secret forKey:@"secret"];
|
|
}
|
|
|
|
+ (MTProxySecret *_Nullable)parse:(NSString *_Nonnull)string {
|
|
NSData *hexData = parseHexString(string);
|
|
if (hexData == nil) {
|
|
NSString *finalString = @"";
|
|
finalString = [finalString
|
|
stringByAppendingString:
|
|
[string
|
|
stringByTrimmingCharactersInSet:
|
|
[NSCharacterSet characterSetWithCharactersInString:@"="]]];
|
|
finalString = [finalString stringByReplacingOccurrencesOfString:@"-"
|
|
withString:@"+"];
|
|
finalString = [finalString stringByReplacingOccurrencesOfString:@"_"
|
|
withString:@"/"];
|
|
while (finalString.length % 4 != 0) {
|
|
finalString = [finalString stringByAppendingString:@"="];
|
|
}
|
|
|
|
hexData = base64_decode(finalString);
|
|
}
|
|
if (hexData != nil) {
|
|
return [self parseData:hexData];
|
|
} else {
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
+ (MTProxySecret *_Nullable)parseData:(NSData *_Nonnull)data {
|
|
if (data == nil || data.length < 16) {
|
|
return nil;
|
|
}
|
|
|
|
uint8_t firstByte = 0;
|
|
[data getBytes:&firstByte length:1];
|
|
|
|
if (data.length == 16) {
|
|
return [[MTProxySecretType0 alloc] initWithSecret:data];
|
|
} else if (data.length == 17) {
|
|
if (firstByte == 0xdd) {
|
|
return [[MTProxySecretType1 alloc]
|
|
initWithSecret:[data subdataWithRange:NSMakeRange(1, 16)]];
|
|
} else {
|
|
return nil;
|
|
}
|
|
} else if (data.length >= 18 && firstByte == 0xee) {
|
|
NSString *domain = [[NSString alloc]
|
|
initWithData:[data subdataWithRange:NSMakeRange(1 + 16,
|
|
data.length - (1 + 16))]
|
|
encoding:NSUTF8StringEncoding];
|
|
if (domain == nil) {
|
|
return nil;
|
|
}
|
|
return [[MTProxySecretType2 alloc]
|
|
initWithSecret:[data subdataWithRange:NSMakeRange(1, 16)]
|
|
domain:domain];
|
|
} else {
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
- (NSData *_Nonnull)serialize {
|
|
assert(false);
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *_Nonnull)serializeToString {
|
|
assert(false);
|
|
return nil;
|
|
}
|
|
|
|
- (NSString *)description {
|
|
return dataToHexString([self serialize]);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTProxySecretType0
|
|
|
|
- (instancetype _Nullable)initWithSecret:(NSData *_Nonnull)secret {
|
|
self = [super initWithSecret:secret];
|
|
if (self != nil) {
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
|
self = [super initWithCoder:aDecoder];
|
|
if (self != nil) {
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
|
[super encodeWithCoder:aCoder];
|
|
}
|
|
|
|
- (NSData *_Nonnull)serialize {
|
|
return self.secret;
|
|
}
|
|
|
|
- (NSString *_Nonnull)serializeToString {
|
|
return dataToHexString(self.serialize);
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object {
|
|
if (![object isKindOfClass:[MTProxySecretType0 class]]) {
|
|
return false;
|
|
}
|
|
MTProxySecretType0 *other = object;
|
|
if (![self.secret isEqual:other.secret]) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTProxySecretType1
|
|
|
|
- (instancetype _Nullable)initWithSecret:(NSData *_Nonnull)secret {
|
|
self = [super initWithSecret:secret];
|
|
if (self != nil) {
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
|
self = [super initWithCoder:aDecoder];
|
|
if (self != nil) {
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
|
[super encodeWithCoder:aCoder];
|
|
}
|
|
|
|
- (NSData *_Nonnull)serialize {
|
|
NSMutableData *data = [[NSMutableData alloc] init];
|
|
uint8_t marker = 0xdd;
|
|
[data appendBytes:&marker length:1];
|
|
[data appendData:self.secret];
|
|
return data;
|
|
}
|
|
|
|
- (NSString *_Nonnull)serializeToString {
|
|
return dataToHexString(self.serialize);
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object {
|
|
if (![object isKindOfClass:[MTProxySecretType1 class]]) {
|
|
return false;
|
|
}
|
|
MTProxySecretType1 *other = object;
|
|
if (![self.secret isEqual:other.secret]) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTProxySecretType2
|
|
|
|
- (instancetype _Nullable)initWithSecret:(NSData *_Nonnull)secret
|
|
domain:(NSString *_Nonnull)domain {
|
|
self = [super initWithSecret:secret];
|
|
if (self != nil) {
|
|
_domain = domain;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
|
self = [super initWithCoder:aDecoder];
|
|
if (self != nil) {
|
|
_domain = [aDecoder decodeObjectForKey:@"domain"];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
|
[super encodeWithCoder:aCoder];
|
|
[aCoder encodeObject:_domain forKey:@"domain"];
|
|
}
|
|
|
|
- (NSData *_Nonnull)serialize {
|
|
NSMutableData *data = [[NSMutableData alloc] init];
|
|
uint8_t marker = 0xee;
|
|
[data appendBytes:&marker length:1];
|
|
[data appendData:self.secret];
|
|
[data appendData:[_domain dataUsingEncoding:NSUTF8StringEncoding]];
|
|
return data;
|
|
}
|
|
|
|
- (NSString *_Nonnull)serializeToString {
|
|
NSData *data = [self serialize];
|
|
if ([data respondsToSelector:@selector(base64EncodedDataWithOptions:)]) {
|
|
return [[data base64EncodedStringWithOptions:kNilOptions]
|
|
stringByTrimmingCharactersInSet:
|
|
[NSCharacterSet characterSetWithCharactersInString:@"="]];
|
|
} else {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
return [self.serialize base64Encoding];
|
|
#pragma clang diagnostic pop
|
|
}
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object {
|
|
if (![object isKindOfClass:[MTProxySecretType2 class]]) {
|
|
return false;
|
|
}
|
|
MTProxySecretType2 *other = object;
|
|
if (![self.secret isEqual:other.secret]) {
|
|
return false;
|
|
}
|
|
if (![self.domain isEqual:other.domain]) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTSocksProxySettings
|
|
|
|
- (instancetype)initWithIp:(NSString *)ip
|
|
port:(uint16_t)port
|
|
username:(NSString *)username
|
|
password:(NSString *)password
|
|
secret:(NSData *)secret {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_ip = ip;
|
|
_port = port;
|
|
_username = username;
|
|
_password = password;
|
|
_secret = secret;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object {
|
|
if (![object isKindOfClass:[MTSocksProxySettings class]]) {
|
|
return false;
|
|
}
|
|
MTSocksProxySettings *other = object;
|
|
if ((other->_ip != nil) != (_ip != nil) ||
|
|
(_ip != nil && ![_ip isEqual:other->_ip])) {
|
|
return false;
|
|
}
|
|
if (other->_port != _port) {
|
|
return false;
|
|
}
|
|
if ((other->_username != nil) != (_username != nil) ||
|
|
(_username != nil && ![_username isEqual:other->_username])) {
|
|
return false;
|
|
}
|
|
if ((other->_password != nil) != (_password != nil) ||
|
|
(_password != nil && ![_password isEqual:other->_password])) {
|
|
return false;
|
|
}
|
|
if ((other->_secret != nil) != (_secret != nil) ||
|
|
(_secret != nil && ![_secret isEqual:other->_secret])) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
- (NSString *)description {
|
|
return
|
|
[NSString stringWithFormat:@"%@:%d+%@+%@+%@", _ip, (int)_port, _username,
|
|
_password, [_secret description]];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTNetworkSettings
|
|
|
|
- (instancetype)initWithReducedBackupDiscoveryTimeout:
|
|
(bool)reducedBackupDiscoveryTimeout {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_reducedBackupDiscoveryTimeout = reducedBackupDiscoveryTimeout;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)isEqual:(id)object {
|
|
if (![object isKindOfClass:[MTNetworkSettings class]]) {
|
|
return false;
|
|
}
|
|
MTNetworkSettings *other = object;
|
|
if (_reducedBackupDiscoveryTimeout != other->_reducedBackupDiscoveryTimeout) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation MTApiEnvironment
|
|
|
|
- (instancetype)init {
|
|
self = [self initWithDeviceModelName:nil];
|
|
if (self != nil) {
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (id _Nonnull)initWithDeviceModelName:(NSString *_Nullable)deviceModelName {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
NSString *spoofedModel = nil;
|
|
NSString *spoofedVersion = nil;
|
|
MTDeviceSpoofResolveValues(defaults, &spoofedModel, &spoofedVersion);
|
|
|
|
if (spoofedModel.length > 0) {
|
|
_deviceModel = spoofedModel;
|
|
} else if (deviceModelName != nil) {
|
|
_deviceModel = deviceModelName;
|
|
} else {
|
|
_deviceModel = [self platformString];
|
|
}
|
|
_deviceModelName = deviceModelName;
|
|
|
|
if (spoofedVersion.length > 0) {
|
|
_systemVersion = spoofedVersion;
|
|
} else {
|
|
#if TARGET_OS_IPHONE
|
|
_systemVersion = [[UIDevice currentDevice] systemVersion];
|
|
#else
|
|
NSProcessInfo *pInfo = [NSProcessInfo processInfo];
|
|
_systemVersion = [[[pInfo operatingSystemVersionString]
|
|
componentsSeparatedByString:@" "] objectAtIndex:1];
|
|
#endif
|
|
}
|
|
|
|
NSString *suffix = @"";
|
|
#if TARGET_OS_OSX
|
|
NSString *value =
|
|
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"SOURCE"];
|
|
if (value != nil) {
|
|
suffix = [NSString stringWithFormat:@"%@", value];
|
|
}
|
|
#endif
|
|
|
|
// SOURCE
|
|
NSString *versionString = [[NSString alloc]
|
|
initWithFormat:@"%@ (%@) %@",
|
|
[[[NSBundle mainBundle] infoDictionary]
|
|
objectForKey:@"CFBundleShortVersionString"],
|
|
[[[NSBundle mainBundle] infoDictionary]
|
|
objectForKey:@"CFBundleVersion"],
|
|
suffix];
|
|
_appVersion = versionString;
|
|
|
|
_systemLangCode = [[NSLocale preferredLanguages] objectAtIndex:0];
|
|
#if TARGET_OS_OSX
|
|
_langPack = @"macos";
|
|
#else
|
|
_langPack = @"ios";
|
|
#endif
|
|
_langPackCode = @"";
|
|
|
|
[self _updateApiInitializationHash];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)_updateApiInitializationHash {
|
|
_apiInitializationHash = [[NSString alloc]
|
|
initWithFormat:
|
|
@"apiId=%" PRId32
|
|
"&deviceModel=%@&systemVersion=%@&appVersion=%@&langCode=%@&layer=%@"
|
|
"&langPack=%@&langPackCode=%@&proxy=%@&systemCode=%@",
|
|
_apiId, _deviceModel, _systemVersion, _appVersion, _systemLangCode,
|
|
_layer, _langPack, _langPackCode, _socksProxySettings, _systemCode];
|
|
}
|
|
|
|
- (void)setLayer:(NSNumber *)layer {
|
|
_layer = layer;
|
|
|
|
[self _updateApiInitializationHash];
|
|
}
|
|
|
|
- (void)setAppVersion:(NSString *)appVersion {
|
|
_appVersion = appVersion;
|
|
|
|
[self _updateApiInitializationHash];
|
|
}
|
|
|
|
- (void)setLangPack:(NSString *)langPack {
|
|
_langPack = langPack;
|
|
|
|
[self _updateApiInitializationHash];
|
|
}
|
|
|
|
- (void)setLangPackCode:(NSString *)langPackCode {
|
|
_langPackCode = langPackCode;
|
|
|
|
[self _updateApiInitializationHash];
|
|
}
|
|
|
|
- (NSString *)platformString {
|
|
#if TARGET_OS_IPHONE
|
|
NSString *platform = [self platform];
|
|
|
|
if ([platform isEqualToString:@"iPhone1,1"])
|
|
return @"iPhone";
|
|
if ([platform isEqualToString:@"iPhone1,2"])
|
|
return @"iPhone 3G";
|
|
if ([platform isEqualToString:@"iPhone2,1"])
|
|
return @"iPhone 3GS";
|
|
if ([platform hasPrefix:@"iPhone3"])
|
|
return @"iPhone 4";
|
|
if ([platform hasPrefix:@"iPhone4"])
|
|
return @"iPhone 4S";
|
|
if ([platform isEqualToString:@"iPhone5,1"] ||
|
|
[platform isEqualToString:@"iPhone5,2"])
|
|
return @"iPhone 5";
|
|
if ([platform isEqualToString:@"iPhone5,3"] ||
|
|
[platform isEqualToString:@"iPhone5,4"])
|
|
return @"iPhone 5C";
|
|
if ([platform hasPrefix:@"iPhone6"])
|
|
return @"iPhone 5S";
|
|
if ([platform isEqualToString:@"iPhone7,1"])
|
|
return @"iPhone 6 Plus";
|
|
if ([platform isEqualToString:@"iPhone7,2"])
|
|
return @"iPhone 6";
|
|
if ([platform isEqualToString:@"iPhone8,1"])
|
|
return @"iPhone 6S";
|
|
if ([platform isEqualToString:@"iPhone8,2"])
|
|
return @"iPhone 6S Plus";
|
|
if ([platform isEqualToString:@"iPhone8,4"])
|
|
return @"iPhone SE";
|
|
if ([platform isEqualToString:@"iPhone9,1"] ||
|
|
[platform isEqualToString:@"iPhone9,3"])
|
|
return @"iPhone 7";
|
|
if ([platform isEqualToString:@"iPhone9,2"] ||
|
|
[platform isEqualToString:@"iPhone9,4"])
|
|
return @"iPhone 7 Plus";
|
|
if ([platform isEqualToString:@"iPhone10,1"] ||
|
|
[platform isEqualToString:@"iPhone10,4"])
|
|
return @"iPhone 8";
|
|
if ([platform isEqualToString:@"iPhone10,2"] ||
|
|
[platform isEqualToString:@"iPhone10,5"])
|
|
return @"iPhone 8 Plus";
|
|
if ([platform isEqualToString:@"iPhone10,3"] ||
|
|
[platform isEqualToString:@"iPhone10,6"])
|
|
return @"iPhone X";
|
|
if ([platform isEqualToString:@"iPhone11,2"])
|
|
return @"iPhone XS";
|
|
if ([platform isEqualToString:@"iPhone11,4"] ||
|
|
[platform isEqualToString:@"iPhone11,6"])
|
|
return @"iPhone XS Max";
|
|
if ([platform isEqualToString:@"iPhone11,8"])
|
|
return @"iPhone XR";
|
|
if ([platform isEqualToString:@"iPhone12,1"])
|
|
return @"iPhone 11";
|
|
if ([platform isEqualToString:@"iPhone12,3"])
|
|
return @"iPhone 11 Pro";
|
|
if ([platform isEqualToString:@"iPhone12,5"])
|
|
return @"iPhone 11 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone12,8"])
|
|
return @"iPhone SE (2nd gen)";
|
|
if ([platform isEqualToString:@"iPhone13,1"])
|
|
return @"iPhone 12 mini";
|
|
if ([platform isEqualToString:@"iPhone13,2"])
|
|
return @"iPhone 12";
|
|
if ([platform isEqualToString:@"iPhone13,3"])
|
|
return @"iPhone 12 Pro";
|
|
if ([platform isEqualToString:@"iPhone13,4"])
|
|
return @"iPhone 12 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone14,2"])
|
|
return @"iPhone 13 Pro";
|
|
if ([platform isEqualToString:@"iPhone14,3"])
|
|
return @"iPhone 13 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone14,4"])
|
|
return @"iPhone 13 Mini";
|
|
if ([platform isEqualToString:@"iPhone14,5"])
|
|
return @"iPhone 13";
|
|
if ([platform isEqualToString:@"iPhone14,6"])
|
|
return @"iPhone SE (3rd gen)";
|
|
if ([platform isEqualToString:@"iPhone14,7"])
|
|
return @"iPhone 14";
|
|
if ([platform isEqualToString:@"iPhone14,8"])
|
|
return @"iPhone 14 Plus";
|
|
if ([platform isEqualToString:@"iPhone15,2"])
|
|
return @"iPhone 14 Pro";
|
|
if ([platform isEqualToString:@"iPhone15,3"])
|
|
return @"iPhone 14 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone15,4"])
|
|
return @"iPhone 15";
|
|
if ([platform isEqualToString:@"iPhone15,5"])
|
|
return @"iPhone 15 Plus";
|
|
if ([platform isEqualToString:@"iPhone16,1"])
|
|
return @"iPhone 15 Pro";
|
|
if ([platform isEqualToString:@"iPhone16,2"])
|
|
return @"iPhone 15 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone17,3"])
|
|
return @"iPhone 16";
|
|
if ([platform isEqualToString:@"iPhone17,4"])
|
|
return @"iPhone 16 Plus";
|
|
if ([platform isEqualToString:@"iPhone17,1"])
|
|
return @"iPhone 16 Pro";
|
|
if ([platform isEqualToString:@"iPhone17,2"])
|
|
return @"iPhone 16 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone17,5"])
|
|
return @"iPhone 16e";
|
|
if ([platform isEqualToString:@"iPhone18,3"])
|
|
return @"iPhone 17";
|
|
if ([platform isEqualToString:@"iPhone18,1"])
|
|
return @"iPhone 17 Pro";
|
|
if ([platform isEqualToString:@"iPhone18,2"])
|
|
return @"iPhone 17 Pro Max";
|
|
if ([platform isEqualToString:@"iPhone18,4"])
|
|
return @"iPhone Air";
|
|
|
|
if ([platform hasPrefix:@"iPod1"])
|
|
return @"iPod touch 1G";
|
|
if ([platform hasPrefix:@"iPod2"])
|
|
return @"iPod touch 2G";
|
|
if ([platform hasPrefix:@"iPod3"])
|
|
return @"iPod touch 3G";
|
|
if ([platform hasPrefix:@"iPod4"])
|
|
return @"iPod touch 4G";
|
|
if ([platform hasPrefix:@"iPod5"])
|
|
return @"iPod touch 5G";
|
|
if ([platform hasPrefix:@"iPod7"])
|
|
return @"iPod touch 6G";
|
|
if ([platform hasPrefix:@"iPod9"])
|
|
return @"iPod touch 7G";
|
|
|
|
if ([platform isEqualToString:@"iPad2,5"] ||
|
|
[platform isEqualToString:@"iPad2,6"] ||
|
|
[platform isEqualToString:@"iPad2,7"])
|
|
return @"iPad mini";
|
|
|
|
if ([platform hasPrefix:@"iPad2"])
|
|
return @"iPad 2G";
|
|
|
|
if ([platform isEqualToString:@"iPad3,1"] ||
|
|
[platform isEqualToString:@"iPad3,2"] ||
|
|
[platform isEqualToString:@"iPad3,3"])
|
|
return @"iPad 3G";
|
|
|
|
if ([platform isEqualToString:@"iPad3,4"] ||
|
|
[platform isEqualToString:@"iPad3,5"] ||
|
|
[platform isEqualToString:@"iPad3,6"])
|
|
return @"iPad 3G";
|
|
|
|
if ([platform isEqualToString:@"iPad4,1"] ||
|
|
[platform isEqualToString:@"iPad4,2"])
|
|
return @"iPad Air";
|
|
|
|
if ([platform isEqualToString:@"iPad4,4"] ||
|
|
[platform isEqualToString:@"iPad4,5"] ||
|
|
[platform isEqualToString:@"iPad4,6"])
|
|
return @"iPad mini Retina";
|
|
|
|
if ([platform isEqualToString:@"iPad4,7"] ||
|
|
[platform isEqualToString:@"iPad4,8"] ||
|
|
[platform isEqualToString:@"iPad4,9"])
|
|
return @"iPad mini 3";
|
|
|
|
if ([platform isEqualToString:@"iPad5,1"] ||
|
|
[platform isEqualToString:@"iPad5,2"])
|
|
return @"iPad mini 4";
|
|
|
|
if ([platform isEqualToString:@"iPad5,3"] ||
|
|
[platform isEqualToString:@"iPad5,4"])
|
|
return @"iPad Air 2";
|
|
|
|
if ([platform isEqualToString:@"iPad6,3"] ||
|
|
[platform isEqualToString:@"iPad6,4"])
|
|
return @"iPad Pro 9.7 inch";
|
|
|
|
if ([platform isEqualToString:@"iPad6,7"] ||
|
|
[platform isEqualToString:@"iPad6,8"])
|
|
return @"iPad Pro 12.9 inch";
|
|
|
|
if ([platform isEqualToString:@"iPad6,11"] ||
|
|
[platform isEqualToString:@"iPad6,12"])
|
|
return @"iPad (2017)";
|
|
|
|
if ([platform isEqualToString:@"iPad7,1"] ||
|
|
[platform isEqualToString:@"iPad7,2"])
|
|
return @"iPad Pro (2nd gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad7,3"] ||
|
|
[platform isEqualToString:@"iPad7,4"])
|
|
return @"iPad Pro 10.5 inch";
|
|
|
|
if ([platform isEqualToString:@"iPad7,5"] ||
|
|
[platform isEqualToString:@"iPad7,6"])
|
|
return @"iPad (6th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad7,11"] ||
|
|
[platform isEqualToString:@"iPad7,12"])
|
|
return @"iPad 10.2 inch (7th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad8,1"] ||
|
|
[platform isEqualToString:@"iPad8,2"] ||
|
|
[platform isEqualToString:@"iPad8,3"] ||
|
|
[platform isEqualToString:@"iPad8,4"])
|
|
return @"iPad Pro 11 inch";
|
|
|
|
if ([platform isEqualToString:@"iPad8,5"] ||
|
|
[platform isEqualToString:@"iPad8,6"] ||
|
|
[platform isEqualToString:@"iPad8,7"] ||
|
|
[platform isEqualToString:@"iPad8,8"])
|
|
return @"iPad Pro 12.9 inch (3rd gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad8,9"] ||
|
|
[platform isEqualToString:@"iPad8,10"])
|
|
return @"iPad Pro 11 inch (2th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad8,11"] ||
|
|
[platform isEqualToString:@"iPad8,12"])
|
|
return @"iPad Pro 12.9 inch (4th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad11,1"] ||
|
|
[platform isEqualToString:@"iPad11,2"])
|
|
return @"iPad mini (5th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad11,3"] ||
|
|
[platform isEqualToString:@"iPad11,4"])
|
|
return @"iPad Air (3rd gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad11,6"] ||
|
|
[platform isEqualToString:@"iPad11,7"])
|
|
return @"iPad (8th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad12,1"] ||
|
|
[platform isEqualToString:@"iPad12,2"])
|
|
return @"iPad (9th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad13,1"] ||
|
|
[platform isEqualToString:@"iPad13,2"])
|
|
return @"iPad Air (4th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad13,4"] ||
|
|
[platform isEqualToString:@"iPad13,5"] ||
|
|
[platform isEqualToString:@"iPad13,6"] ||
|
|
[platform isEqualToString:@"iPad13,7"])
|
|
return @"iPad Pro 11 inch (3th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad13,8"] ||
|
|
[platform isEqualToString:@"iPad13,9"] ||
|
|
[platform isEqualToString:@"iPad13,10"] ||
|
|
[platform isEqualToString:@"iPad13,11"])
|
|
return @"iPad Pro 12.9 inch (5th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad13,16"] ||
|
|
[platform isEqualToString:@"iPad13,17"])
|
|
return @"iPad Air (5th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad13,18"] ||
|
|
[platform isEqualToString:@"iPad13,19"])
|
|
return @"iPad (10th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad14,1"] ||
|
|
[platform isEqualToString:@"iPad14,2"])
|
|
return @"iPad mini (6th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad14,3"] ||
|
|
[platform isEqualToString:@"iPad14,4"])
|
|
return @"iPad Pro 11 inch (4th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad14,5"] ||
|
|
[platform isEqualToString:@"iPad14,6"])
|
|
return @"iPad Pro 12.9 inch (6th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad14,8"] ||
|
|
[platform isEqualToString:@"iPad14,9"])
|
|
return @"iPad Air (6th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad14,10"] ||
|
|
[platform isEqualToString:@"iPad14,11"])
|
|
return @"iPad Air (7th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad16,3"] ||
|
|
[platform isEqualToString:@"iPad16,4"])
|
|
return @"iPad Pro 11 inch (5th gen)";
|
|
|
|
if ([platform isEqualToString:@"iPad16,5"] ||
|
|
[platform isEqualToString:@"iPad16,6"])
|
|
return @"iPad Pro 12.9 inch (7th gen)";
|
|
|
|
if ([platform hasPrefix:@"iPhone"])
|
|
return @"Unknown iPhone";
|
|
if ([platform hasPrefix:@"iPod"])
|
|
return @"Unknown iPod";
|
|
if ([platform hasPrefix:@"iPad"])
|
|
return @"Unknown iPad";
|
|
|
|
if ([platform hasSuffix:@"86"] || [platform isEqual:@"x86_64"] ||
|
|
[platform isEqual:@"arm64"]) {
|
|
return @"iPhone Simulator";
|
|
}
|
|
#else
|
|
return [self macHWName];
|
|
#endif
|
|
|
|
return @"Unknown iOS device";
|
|
}
|
|
|
|
- (NSString *)macHWName {
|
|
size_t len = 0;
|
|
sysctlbyname("hw.model", NULL, &len, NULL, 0);
|
|
if (len) {
|
|
char *model = malloc(len * sizeof(char));
|
|
sysctlbyname("hw.model", model, &len, NULL, 0);
|
|
NSString *name = [[NSString alloc] initWithUTF8String:model];
|
|
free(model);
|
|
return name;
|
|
};
|
|
return @"macOS";
|
|
}
|
|
|
|
- (NSString *)getSysInfoByName:(char *)typeSpecifier {
|
|
size_t size;
|
|
sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
|
|
|
|
char *answer = malloc(size);
|
|
sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
|
|
|
|
NSString *results = [NSString stringWithCString:answer
|
|
encoding:NSUTF8StringEncoding];
|
|
|
|
free(answer);
|
|
return results;
|
|
}
|
|
|
|
- (NSString *)platform {
|
|
return [self getSysInfoByName:"hw.machine"];
|
|
}
|
|
|
|
- (MTApiEnvironment *)withUpdatedLangPackCode:(NSString *)langPackCode {
|
|
MTApiEnvironment *result =
|
|
[[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
|
|
|
|
result.apiId = self.apiId;
|
|
result.appVersion = self.appVersion;
|
|
result.layer = self.layer;
|
|
|
|
result.langPack = self.langPack;
|
|
|
|
result->_langPackCode = langPackCode;
|
|
|
|
result.disableUpdates = self.disableUpdates;
|
|
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
|
|
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
|
|
result.accessHostOverride = self.accessHostOverride;
|
|
result->_socksProxySettings = self.socksProxySettings;
|
|
result->_networkSettings = self.networkSettings;
|
|
result->_systemCode = self.systemCode;
|
|
|
|
[result _updateApiInitializationHash];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (instancetype)copyWithZone:(NSZone *)__unused zone {
|
|
MTApiEnvironment *result =
|
|
[[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
|
|
|
|
result.apiId = self.apiId;
|
|
result.appVersion = self.appVersion;
|
|
result.layer = self.layer;
|
|
|
|
result.langPack = self.langPack;
|
|
|
|
result->_langPackCode = self.langPackCode;
|
|
result->_socksProxySettings = self.socksProxySettings;
|
|
result->_networkSettings = self.networkSettings;
|
|
result->_systemCode = self.systemCode;
|
|
|
|
result.disableUpdates = self.disableUpdates;
|
|
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
|
|
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
|
|
result.accessHostOverride = self.accessHostOverride;
|
|
|
|
[result _updateApiInitializationHash];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (MTApiEnvironment *)withUpdatedSocksProxySettings:
|
|
(MTSocksProxySettings *)socksProxySettings {
|
|
MTApiEnvironment *result =
|
|
[[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
|
|
|
|
result.apiId = self.apiId;
|
|
result.appVersion = self.appVersion;
|
|
result.layer = self.layer;
|
|
|
|
result.langPack = self.langPack;
|
|
|
|
result->_langPackCode = self.langPackCode;
|
|
result->_socksProxySettings = socksProxySettings;
|
|
result->_networkSettings = self.networkSettings;
|
|
result->_systemCode = self.systemCode;
|
|
|
|
result.disableUpdates = self.disableUpdates;
|
|
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
|
|
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
|
|
result.accessHostOverride = self.accessHostOverride;
|
|
|
|
[result _updateApiInitializationHash];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (MTApiEnvironment *)withUpdatedNetworkSettings:
|
|
(MTNetworkSettings *)networkSettings {
|
|
MTApiEnvironment *result =
|
|
[[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
|
|
|
|
result.apiId = self.apiId;
|
|
result.appVersion = self.appVersion;
|
|
result.layer = self.layer;
|
|
|
|
result.langPack = self.langPack;
|
|
|
|
result->_langPackCode = self.langPackCode;
|
|
result->_socksProxySettings = self.socksProxySettings;
|
|
result->_networkSettings = networkSettings;
|
|
result->_systemCode = self.systemCode;
|
|
|
|
result.disableUpdates = self.disableUpdates;
|
|
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
|
|
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
|
|
result.accessHostOverride = self.accessHostOverride;
|
|
|
|
[result _updateApiInitializationHash];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (MTApiEnvironment *)withUpdatedSystemCode:(NSData *)systemCode {
|
|
MTApiEnvironment *result =
|
|
[[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName];
|
|
|
|
result.apiId = self.apiId;
|
|
result.appVersion = self.appVersion;
|
|
result.layer = self.layer;
|
|
|
|
result.langPack = self.langPack;
|
|
|
|
result->_langPackCode = self.langPackCode;
|
|
result->_socksProxySettings = self.socksProxySettings;
|
|
result->_networkSettings = self.networkSettings;
|
|
result->_systemCode = systemCode;
|
|
|
|
result.disableUpdates = self.disableUpdates;
|
|
result.tcpPayloadPrefix = self.tcpPayloadPrefix;
|
|
result.datacenterAddressOverrides = self.datacenterAddressOverrides;
|
|
result.accessHostOverride = self.accessHostOverride;
|
|
|
|
[result _updateApiInitializationHash];
|
|
|
|
return result;
|
|
}
|
|
|
|
@end
|