Merge branch 'master' into holes

This commit is contained in:
Peter
2019-03-24 20:50:05 +04:00
36 changed files with 802 additions and 895 deletions

View File

@@ -344,7 +344,7 @@ private final class SharedApplicationContext {
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
let networkArguments = NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManager.voipMaxLayer)
let networkArguments = NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: PresentationCallManager.voipMaxLayer, appData: BuildConfig.shared().bundleData)
let appGroupName = "group.\(Bundle.main.bundleIdentifier!)"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
@@ -1076,8 +1076,8 @@ private final class SharedApplicationContext {
}
})
if !BuildConfig.shared().hockeyAppId.isEmpty {
BITHockeyManager.shared().configure(withIdentifier: BuildConfig.shared().hockeyAppId, delegate: self)
if let hockeyAppId = BuildConfig.shared().hockeyAppId, !hockeyAppId.isEmpty {
BITHockeyManager.shared().configure(withIdentifier: hockeyAppId, delegate: self)
BITHockeyManager.shared().crashManager.crashManagerStatus = .alwaysAsk
BITHockeyManager.shared().start()
BITHockeyManager.shared().authenticator.authenticateInstallation()
@@ -1612,81 +1612,84 @@ private final class SharedApplicationContext {
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
if let peerId = peerIdFromNotification(response.notification) {
var messageId: MessageId? = nil
if response.notification.request.content.categoryIdentifier == "watch" {
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
}
self.openChatWhenReady(accountId: accountIdFromNotification(response.notification), peerId: peerId, messageId: messageId)
}
completionHandler()
} else if response.actionIdentifier == "reply", let peerId = peerIdFromNotification(response.notification), let accountId = accountIdFromNotification(response.notification) {
guard let response = response as? UNTextInputNotificationResponse, !response.userText.isEmpty else {
completionHandler()
return
}
let text = response.userText
let signal = self.sharedContextPromise.get()
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { sharedContext -> Signal<Void, NoError> in
sharedContext.wakeupManager.allowBackgroundTimeExtension(timeout: 4.0)
return sharedContext.sharedContext.activeAccounts
|> mapToSignal { _, accounts, _ -> Signal<Account, NoError> in
for account in accounts {
if account.1.id == accountId {
return .single(account.1)
}
let _ = (accountIdFromNotification(response.notification, sharedContext: self.sharedContextPromise.get())
|> deliverOnMainQueue).start(next: { accountId in
if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
if let peerId = peerIdFromNotification(response.notification) {
var messageId: MessageId? = nil
if response.notification.request.content.categoryIdentifier == "watch" {
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
}
return .complete()
self.openChatWhenReady(accountId: accountId, peerId: peerId, messageId: messageId)
}
completionHandler()
} else if response.actionIdentifier == "reply", let peerId = peerIdFromNotification(response.notification), let accountId = accountId {
guard let response = response as? UNTextInputNotificationResponse, !response.userText.isEmpty else {
completionHandler()
return
}
let text = response.userText
let signal = self.sharedContextPromise.get()
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { account -> Signal<Void, NoError> in
if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) {
let _ = applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0)).start()
}
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
|> map { messageIds -> MessageId? in
if messageIds.isEmpty {
return nil
} else {
return messageIds[0]
}
}
|> mapToSignal { messageId -> Signal<Void, NoError> in
if let messageId = messageId {
return account.postbox.unsentMessageIdsView()
|> filter { view in
return !view.ids.contains(messageId)
|> mapToSignal { sharedContext -> Signal<Void, NoError> in
sharedContext.wakeupManager.allowBackgroundTimeExtension(timeout: 4.0)
return sharedContext.sharedContext.activeAccounts
|> mapToSignal { _, accounts, _ -> Signal<Account, NoError> in
for account in accounts {
if account.1.id == accountId {
return .single(account.1)
}
|> take(1)
|> mapToSignal { _ -> Signal<Void, NoError> in
}
return .complete()
}
|> take(1)
|> deliverOnMainQueue
|> mapToSignal { account -> Signal<Void, NoError> in
if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) {
let _ = applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0)).start()
}
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
|> map { messageIds -> MessageId? in
if messageIds.isEmpty {
return nil
} else {
return messageIds[0]
}
}
|> mapToSignal { messageId -> Signal<Void, NoError> in
if let messageId = messageId {
return account.postbox.unsentMessageIdsView()
|> filter { view in
return !view.ids.contains(messageId)
}
|> take(1)
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
} else {
return .complete()
}
} else {
return .complete()
}
}
}
}
|> deliverOnMainQueue
let disposable = MetaDisposable()
disposable.set((signal
|> afterDisposed { [weak disposable] in
Queue.mainQueue().async {
if let disposable = disposable {
self.replyFromNotificationsDisposables.remove(disposable)
|> deliverOnMainQueue
let disposable = MetaDisposable()
disposable.set((signal
|> afterDisposed { [weak disposable] in
Queue.mainQueue().async {
if let disposable = disposable {
self.replyFromNotificationsDisposables.remove(disposable)
}
completionHandler()
}
completionHandler()
}
}).start())
self.replyFromNotificationsDisposables.add(disposable)
} else {
completionHandler()
}
}).start())
self.replyFromNotificationsDisposables.add(disposable)
} else {
completionHandler()
}
})
}
private func registerForNotifications(context: AccountContext, authorize: Bool = true, completion: @escaping (Bool) -> Void = { _ in }) {
@@ -1731,7 +1734,7 @@ private final class SharedApplicationContext {
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
replyLegacyMessageCategory = UNNotificationCategory(identifier: "r", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
replyLegacyMediaMessageCategory = UNNotificationCategory(identifier: "m", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
legacyChannelMessageCategory = UNNotificationCategory(identifier: "c", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
legacyChannelMessageCategory = UNNotificationCategory(identifier: "c", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
replyMediaMessageCategory = UNNotificationCategory(identifier: "withReplyMedia", actions: [reply], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
@@ -1884,11 +1887,14 @@ private final class SharedApplicationContext {
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
if let context = self.contextValue {
if let accountId = accountIdFromNotification(notification), context.context.account.id != accountId {
completionHandler([.alert])
let _ = (accountIdFromNotification(notification, sharedContext: self.sharedContextPromise.get())
|> deliverOnMainQueue).start(next: { accountId in
if let context = self.contextValue {
if let accountId = accountId, context.context.account.id != accountId {
completionHandler([.alert])
}
}
}
})
}
override var next: UIResponder? {
@@ -1913,13 +1919,70 @@ private final class SharedApplicationContext {
}
}
@available(iOS 10.0, *)
private func accountIdFromNotification(_ notification: UNNotification) -> AccountRecordId? {
if let id = notification.request.content.userInfo["accountId"] as? Int64 {
return AccountRecordId(rawValue: id)
} else {
private func notificationPayloadKey(data: Data) -> Data? {
if data.count < 8 {
return nil
}
return data.subdata(in: 0 ..< 8)
}
@available(iOS 10.0, *)
private func accountIdFromNotification(_ notification: UNNotification, sharedContext: Signal<SharedApplicationContext, NoError>) -> Signal<AccountRecordId?, NoError> {
if let id = notification.request.content.userInfo["accountId"] as? Int64 {
return .single(AccountRecordId(rawValue: id))
} else {
var encryptedData: Data?
if var encryptedPayload = notification.request.content.userInfo["p"] as? String {
encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+")
encryptedPayload = encryptedPayload.replacingOccurrences(of: "_", with: "/")
while encryptedPayload.count % 4 != 0 {
encryptedPayload.append("=")
}
encryptedData = Data(base64Encoded: encryptedPayload)
}
if let encryptedData = encryptedData, let notificationKeyId = notificationPayloadKey(data: encryptedData) {
return sharedContext
|> take(1)
|> mapToSignal { sharedContext -> Signal<AccountRecordId?, NoError> in
return sharedContext.sharedContext.activeAccounts
|> take(1)
|> mapToSignal { _, accounts, _ -> Signal<AccountRecordId?, NoError> in
let keys = accounts.map { _, account, _ -> Signal<(AccountRecordId, MasterNotificationKey)?, NoError> in
return masterNotificationsKey(account: account, ignoreDisabled: true)
|> map { key in
return (account.id, key)
}
}
return combineLatest(keys)
|> map { keys -> AccountRecordId? in
for idAndKey in keys {
if let (id, key) = idAndKey, key.id == notificationKeyId {
return id
}
}
return nil
}
}
}
} else if let userId = notification.request.content.userInfo["userId"] as? Int {
return sharedContext
|> take(1)
|> mapToSignal { sharedContext -> Signal<AccountRecordId?, NoError> in
return sharedContext.sharedContext.activeAccounts
|> take(1)
|> map { _, accounts, _ -> AccountRecordId? in
for (_, account, _) in accounts {
if Int(account.peerId.id) == userId {
return account.id
}
}
return nil
}
}
} else {
return .single(nil)
}
}
}
@available(iOS 10.0, *)

View File

@@ -649,7 +649,7 @@ final class AuthorizedApplicationContext {
if !didAppear {
Queue.mainQueue().after(0.15, {
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments.init(presentationAnimation: .modalSheet))
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})
}
} else {
@@ -698,7 +698,7 @@ final class AuthorizedApplicationContext {
if let strongSelf = self{
for text in alerts {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
let controller = textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root))
}
}
@@ -712,10 +712,10 @@ final class AuthorizedApplicationContext {
})
let importableContacts = self.context.sharedContext.contactDataManager?.importable() ?? .single([:])
self.context.account.importableContacts.set(self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings])
|> mapToSignal { sharedData -> Signal<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], NoError> in
let settings: ContactSynchronizationSettings = (sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings) ?? .defaultSettings
if settings.synchronizeDeviceContacts {
self.context.account.importableContacts.set(self.context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings])
|> mapToSignal { preferences -> Signal<[DeviceContactNormalizedPhoneNumber: ImportableDeviceContactData], NoError> in
let settings: ContactsSettings = (preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings) ?? .defaultSettings
if settings.synchronizeContacts {
return importableContacts
} else {
return .single([:])
@@ -783,7 +783,7 @@ final class AuthorizedApplicationContext {
navigateToMessage()
} else {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.WatchRemote_AlertTitle, text: presentationData.strings.WatchRemote_AlertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.WatchRemote_AlertOpen, action:navigateToMessage)])
let controller = textAlertController(context: strongSelf.context, title: presentationData.strings.WatchRemote_AlertTitle, text: presentationData.strings.WatchRemote_AlertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.WatchRemote_AlertOpen, action:navigateToMessage)])
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root))
}
} else {
@@ -840,7 +840,7 @@ final class AuthorizedApplicationContext {
}
func openRootSearch() {
self.rootController.openChatsSearch()
self.rootController.openChatsController(activateSearch: true)
}
func openRootCompose() {

View File

@@ -4,7 +4,8 @@
+ (instancetype _Nonnull)sharedBuildConfig;
@property (nonatomic, strong, readonly) NSString * _Nonnull hockeyAppId;
@property (nonatomic, strong, readonly) NSData * _Nullable bundleData;
@property (nonatomic, strong, readonly) NSString * _Nullable hockeyAppId;
@property (nonatomic, readonly) int32_t apiId;
@property (nonatomic, strong, readonly) NSString * _Nonnull apiHash;
@property (nonatomic, readonly) bool isInternalBuild;

View File

@@ -1,7 +1,265 @@
#import "BuildConfig.h"
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#import <MtProtoKitDynamic/MtProtoKitDynamic.h>
static uint32_t funcSwap32(uint32_t input)
{
return OSSwapBigToHostInt32(input);
}
static uint32_t funcNoSwap32(uint32_t input)
{
return OSSwapLittleToHostInt32(input);
}
/*
* Magic numbers used by Code Signing
*/
enum {
kSecCodeMagicRequirement = 0xfade0c00, /* single requirement */
kSecCodeMagicRequirementSet = 0xfade0c01, /* requirement set */
kSecCodeMagicCodeDirectory = 0xfade0c02, /* CodeDirectory */
kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
kSecCodeMagicDetachedSignature = 0xfade0cc1, /* detached multi-architecture signature */
kSecCodeMagicEntitlement = 0xfade7171, /* entitlement blob */
kSecCodeMagicByte = 0xfa /* shared first byte */
};
/*
* Structure of an embedded-signature SuperBlob
*/
typedef struct __BlobIndex {
uint32_t type; /* type of entry */
uint32_t offset; /* offset of entry */
} CS_BlobIndex;
typedef struct __Blob {
uint32_t magic; /* magic number */
uint32_t length; /* total length of SuperBlob */
} CS_Blob;
typedef struct __SuperBlob {
CS_Blob blob;
uint32_t count; /* number of index entries following */
CS_BlobIndex index[]; /* (count) entries */
/* followed by Blobs in no particular order as indicated by offsets in index */
} CS_SuperBlob;
/*
* C form of a CodeDirectory.
*/
typedef struct __CodeDirectory {
uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */
uint32_t length; /* total length of CodeDirectory blob */
uint32_t version; /* compatibility version */
uint32_t flags; /* setup and mode flags */
uint32_t hashOffset; /* offset of hash slot element at index zero */
uint32_t identOffset; /* offset of identifier string */
uint32_t nSpecialSlots; /* number of special hash slots */
uint32_t nCodeSlots; /* number of ordinary (code) hash slots */
uint32_t codeLimit; /* limit to main image signature range */
uint8_t hashSize; /* size of each hash in bytes */
uint8_t hashType; /* type of hash (cdHashType* constants) */
uint8_t spare1; /* unused (must be zero) */
uint8_t pageSize; /* log2(page size in bytes); 0 => infinite */
uint32_t spare2; /* unused (must be zero) */
/* followed by dynamic content as located by offset fields above */
} CS_CodeDirectory;
static MTPKCS * _Nullable parseSignature(const char* buffer, size_t size) {
CS_SuperBlob* sb = (CS_SuperBlob*)buffer;
if (OSSwapBigToHostInt32(sb->blob.magic) != kSecCodeMagicEmbeddedSignature)
{
return 0;
}
uint32_t count = OSSwapBigToHostInt32(sb->count);
for (uint32_t i = 0; i < count; i++)
{
uint32_t offset = OSSwapBigToHostInt32(sb->index[i].offset);
const CS_Blob* blob = (const CS_Blob*)(buffer + offset);
if (OSSwapBigToHostInt32(blob->magic) == 0xfade0b01) // signature
{
printf("Embedded signature, length: %d\n", OSSwapBigToHostInt32(blob->length));
if (OSSwapBigToHostInt32(blob->length) != 8)
{
const unsigned char* message = (const unsigned char*)buffer + offset + 8;
MTPKCS *result = [MTPKCS parse:message size:(OSSwapBigToHostInt32(blob->length) - 8)];
return result;
}
}
}
return nil;
}
static MTPKCS * _Nullable parseArch(const char* buffer, size_t size) {
uint32_t (*swap32)(uint32_t) = funcNoSwap32;
uint32_t offset = 0;
const struct mach_header* header = (struct mach_header*)(buffer + offset);
switch (header->magic) {
case MH_CIGAM:
swap32 = funcSwap32;
case MH_MAGIC:
offset += sizeof(struct mach_header);
break;
case MH_CIGAM_64:
swap32 = funcSwap32;
case MH_MAGIC_64:
offset += sizeof(struct mach_header_64);
break;
default:
return nil;
}
const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(swap32(header->cputype), swap32(header->cpusubtype));
if (archInfo != NULL) {
printf("Architecture: %s\n", archInfo->name);
}
uint32_t commandCount = swap32(header->ncmds);
for (uint32_t i = 0; i < commandCount; i++) {
const struct load_command* loadCommand = (const struct load_command*)(buffer + offset);
uint32_t commandSize = swap32(loadCommand->cmdsize);
uint32_t commandType = swap32(loadCommand->cmd);
if (commandType == LC_CODE_SIGNATURE) {
const struct linkedit_data_command* dataCommand = (const struct linkedit_data_command*)(buffer + offset);
uint32_t dataOffset = swap32(dataCommand->dataoff);
uint32_t dataSize = swap32(dataCommand->datasize);
return parseSignature(buffer + dataOffset, dataSize);
}
offset += commandSize;
}
return nil;
}
static MTPKCS * _Nullable parseFat(const char *buffer, size_t size) {
size_t offset = 0;
const struct fat_header* fatHeader = (const struct fat_header*)(buffer + offset);
offset += sizeof(*fatHeader);
uint32_t archCount = OSSwapBigToHostInt32(fatHeader->nfat_arch);
for (uint32_t i = 0; i < archCount; i++) {
const struct fat_arch* arch = (const struct fat_arch*)(buffer + offset);
offset += sizeof(*arch);
uint32_t archOffset = OSSwapBigToHostInt32(arch->offset);
uint32_t archSize = OSSwapBigToHostInt32(arch->size);
MTPKCS *result = parseArch(buffer + archOffset, archSize);
if (result != nil) {
return result;
}
}
return nil;
}
static MTPKCS * _Nullable parseMachO(const char* buffer, size_t size) {
const uint32_t* magic = (const uint32_t*)buffer;
if (*magic == FAT_CIGAM || *magic == FAT_MAGIC) {
return parseFat(buffer, size);
} else {
return parseArch(buffer, size);
}
}
static MTPKCS * _Nullable checkSignature(const char *filename) {
char *buffer = NULL;
int fd = open(filename, O_RDONLY);
if (fd == -1) {
return nil;
}
struct stat st;
fstat(fd, &st);
buffer = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0);
if (buffer == MAP_FAILED) {
if (buffer) {
munmap(buffer, (size_t)st.st_size);
}
if (fd != -1) {
close(fd);
}
return nil;
}
MTPKCS *result = parseMachO(buffer, (size_t)st.st_size);
if (buffer) {
munmap(buffer, (size_t)st.st_size);
}
if (fd != -1) {
close(fd);
}
return result;
}
@interface BuildConfig () {
NSData * _Nullable _bundleData;
int32_t _apiId;
NSString * _Nonnull _apiHash;
NSString * _Nullable _hockeyAppId;
}
@end
@implementation BuildConfig
+ (NSString *)bundleId {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass,
@"bundleSeedID", kSecAttrAccount,
@"", kSecAttrService,
(id)kCFBooleanTrue, kSecReturnAttributes,
nil];
CFDictionaryRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
if (status == errSecItemNotFound) {
status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
}
if (status != errSecSuccess) {
return nil;
}
NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup];
NSArray *components = [accessGroup componentsSeparatedByString:@"."];
NSString *bundleSeedID = [[components objectEnumerator] nextObject];
CFRelease(result);
return bundleSeedID;
}
+ (instancetype _Nonnull)sharedBuildConfig {
static BuildConfig *instance = nil;
static dispatch_once_t onceToken;
@@ -11,16 +269,101 @@
return instance;
}
- (instancetype)init {
self = [super init];
if (self != nil) {
char buf[3];
buf[2] = '\0';
NSString *hex = @(APP_CONFIG_DATA);
assert(0 == [hex length] % 2);
unsigned char *bytes = malloc([hex length]/2);
unsigned char *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);
assert(b2 == buf + 2);
}
NSMutableData *data = [NSMutableData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
if ([data length] == 0) {
assert(false);
}
const char *streamCode = "Cypher";
int keyLength = (int)strlen(streamCode);
int keyOffset = 0;
for (NSUInteger i = 0; i < data.length; i++) {
((uint8_t *)data.mutableBytes)[i] ^= ((uint8_t *)streamCode)[keyOffset % keyLength];
keyOffset += 1;
}
int offset = 0;
uint32_t header = 0;
[data getBytes:&header range:NSMakeRange(offset, 4)];
offset += 4;
if (header != 0xabcdef01U) {
assert(false);
}
[data getBytes:&_apiId range:NSMakeRange(offset, 4)];
offset += 4;
int32_t apiHashLength = 0;
[data getBytes:&apiHashLength range:NSMakeRange(offset, 4)];
offset += 4;
if (apiHashLength > 0) {
_apiHash = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, apiHashLength)] encoding:NSUTF8StringEncoding];
offset += apiHashLength;
} else {
assert(false);
}
int32_t hockeyappIdLength = 0;
[data getBytes:&hockeyappIdLength range:NSMakeRange(offset, 4)];
offset += 4;
if (hockeyappIdLength > 0) {
_hockeyAppId = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(offset, hockeyappIdLength)] encoding:NSUTF8StringEncoding];
offset += hockeyappIdLength;
}
NSString *bundleId = [BuildConfig bundleId];
MTPKCS *signature = checkSignature([[[NSBundle mainBundle] executablePath] UTF8String]);
NSMutableDictionary *dataDict = [[NSMutableDictionary alloc] init];
if (bundleId != nil) {
dataDict[@"bundleId"] = bundleId;
}
if (signature.name != nil) {
dataDict[@"name"] = signature.name;
}
if (signature.data != nil) {
dataDict[@"data"] = [MTSha1(signature.data) base64EncodedStringWithOptions:0];
}
_bundleData = [NSJSONSerialization dataWithJSONObject:dataDict options:0 error:nil];
}
return self;
}
- (NSData * _Nullable)bundleData {
return _bundleData;
}
- (int32_t)apiId {
return APP_CONFIG_API_ID;
return _apiId;
}
- (NSString * _Nonnull)apiHash {
return @(APP_CONFIG_API_HASH);
return _apiHash;
}
- (NSString * _Nonnull)hockeyAppId {
return @(APP_CONFIG_HOCKEYAPPID);
- (NSString * _Nullable)hockeyAppId {
return _hockeyAppId;
}
- (bool)isInternalBuild {

View File

@@ -1 +1 @@
#include "../../Telegram-iOS-Shared/Config-AppStore.xcconfig"
#include "../../Telegram-iOS-Shared/Config/AppStore/Config.xcconfig"

View File

@@ -1 +1 @@
#include "../../Telegram-iOS-Shared/Config-AppStoreLLC.xcconfig"
#include "../../Telegram-iOS-Shared/Config/AppStoreLLC/Config.xcconfig"

View File

@@ -1 +0,0 @@
#include "../../Telegram-iOS-Shared/Config-Hockeyapp Internal.xcconfig"

View File

@@ -0,0 +1 @@
#include "../../Telegram-iOS-Shared/Config/Hockeyapp-Internal/Config.xcconfig"

View File

@@ -1 +0,0 @@
#include "../../Telegram-iOS-Shared/Config-Hockeyapp.xcconfig"

View File

@@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.4.1</string>
<string>5.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -452,14 +452,6 @@ func importLegacyPreferences(accountManager: AccountManager, account: TemporaryA
return settings
})
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings, { current in
var settings: ContactSynchronizationSettings = current as? ContactSynchronizationSettings ?? .defaultSettings
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
settings.synchronizeDeviceContacts = false
}
return settings
})
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
}
@@ -469,6 +461,13 @@ func importLegacyPreferences(accountManager: AccountManager, account: TemporaryA
}
return account.postbox.transaction { transaction -> Void in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
settings.synchronizeContacts = false
}
return settings
})
}
}
|> switchToLatest

View File

@@ -86,7 +86,7 @@ func makeBridgeMedia(message: Message, strings: PresentationStrings, chatPeer: P
if let forward = message.forwardInfo {
let bridgeForward = TGBridgeForwardedMessageMediaAttachment()
bridgeForward.peerId = makeBridgeIdentifier(forward.author.id)
bridgeForward.peerId = forward.author.flatMap({ makeBridgeIdentifier($0.id) }) ?? 0
if let sourceMessageId = forward.sourceMessageId {
bridgeForward.mid = sourceMessageId.id
}

View File

@@ -65,7 +65,7 @@
"PUSH_CHANNEL_MESSAGE_GIF" = "%1$@ posted a GIF";
"PUSH_CHANNEL_MESSAGES" = "%1$@ posted %2$@ messages";
"PUSH_PINNED_TEXT" = "%1$@ pinned \"%2$@\"";
"PUSH_PINNED_TEXT" = "%1$@ pinned \"%2$@\" ";
"PUSH_PINNED_NOTEXT" = "%1$@ pinned a message";
"PUSH_PINNED_PHOTO" = "%1$@ pinned a photo";
"PUSH_PINNED_VIDEO" = "%1$@ pinned a video";
@@ -188,7 +188,7 @@
"PUSH_CHAT_MESSAGES_1" = "%2$@|%1$@ sent a message";
"PUSH_CHAT_MESSAGES_any" = "%2$@|%1$@ sent %3$d messages";
"PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\"";
"PUSH_PINNED_TEXT" = "%1$@|pinned \"%2$@\" ";
"PUSH_PINNED_NOTEXT" = "%1$@|pinned a message";
"PUSH_PINNED_PHOTO" = "%1$@|pinned a photo";
"PUSH_PINNED_VIDEO" = "%1$@|pinned a video";
@@ -500,9 +500,9 @@
"Notification.Kicked" = "%@ removed %@";
"Notification.CreatedChat" = "%@ created a group";
"Notification.CreatedChannel" = "Channel created";
"Notification.CreatedChatWithTitle" = "%@ created the group \"%@\"";
"Notification.CreatedChatWithTitle" = "%@ created the group \"%@\" ";
"Notification.Joined" = "%@ joined Telegram";
"Notification.ChangedGroupName" = "%@ changed group name to \"%@\"";
"Notification.ChangedGroupName" = "%@ changed group name to \"%@\" ";
"Notification.NewAuthDetected" = "%1$@,\nWe detected a login into your account from a new device on %2$@, %3$@ at %4$@\n\nDevice: %5$@\nLocation: %6$@\n\nIf this wasn't you, you can go to Settings — Privacy and Security — Sessions and terminate that session.\n\nIf you think that somebody logged in to your account against your will, you can enable two-step verification in Privacy and Security settings.\n\nSincerely,\nThe Telegram Team";
"Notification.MessageLifetimeChanged" = "%1$@ set the self-destruct timer to %2$@";
"Notification.MessageLifetimeChangedOutgoing" = "You set the self-destruct timer to %1$@";
@@ -1488,7 +1488,7 @@
"Channel.MessagePhotoUpdated" = "Channel photo updated";
"Channel.MessagePhotoRemoved" = "Channel photo removed";
"Channel.MessageTitleUpdated" = "Channel renamed to \"%@\"";
"Channel.MessageTitleUpdated" = "Channel renamed to \"%@\" ";
"Channel.TitleInfo" = "Channel Info";
"Channel.UpdatePhotoItem" = "Set Channel Photo";
@@ -1896,7 +1896,7 @@
"Group.Username.InvalidTooShort" = "Group names must have at least 5 characters.";
"Group.Username.InvalidStartsWithNumber" = "Group names can't start with a number.";
"Notification.PinnedTextMessage" = "%@ pinned \"%@\"";
"Notification.PinnedTextMessage" = "%@ pinned \"%@\" ";
"Notification.PinnedPhotoMessage" = "%@ pinned a photo";
"Notification.PinnedVideoMessage" = "%@ pinned a video";
"Notification.PinnedRoundMessage" = "%@ pinned a video message";
@@ -1909,7 +1909,7 @@
"Notification.PinnedDeletedMessage" = "%@ pinned deleted message";
"Notification.PinnedPollMessage" = "%@ pinned a poll";
"Message.PinnedTextMessage" = "pinned \"%@\"";
"Message.PinnedTextMessage" = "pinned \"%@\" ";
"Message.PinnedPhotoMessage" = "pinned photo";
"Message.PinnedVideoMessage" = "pinned video";
"Message.PinnedAudioMessage" = "pinned voice message";
@@ -3052,7 +3052,7 @@ Unused sets are archived when you add more.";
"Appearance.ThemeNight" = "Night";
"Appearance.ThemeNightBlue" = "Night Blue";
"Appearance.PreviewReplyAuthor" = "Lucio";
"Appearance.PreviewReplyText" = "Reinhart, we need to find you some...";
"Appearance.PreviewReplyText" = "Reinhardt, we need to find you some...";
"Appearance.PreviewIncomingText" = "Ah you kids today with techno music! Enjoy the classics, like Hasselhoff!";
"Appearance.PreviewOutgoingText" = "I can't take you seriously right now. Sorry..";
"Appearance.AccentColor" = "Accent Color";
@@ -4056,3 +4056,142 @@ Unused sets are archived when you add more.";
"NotificationSettings.ShowNotificationsAllAccounts" = "All Accounts";
"NotificationSettings.ShowNotificationsAllAccountsInfoOn" = "Turn this off if you want to receive notifications only from your active account.";
"NotificationSettings.ShowNotificationsAllAccountsInfoOff" = "Turn this on if you want to receive notifications from all your accounts.";
"Gif.Search" = "Search GIFs";
"Gif.NoGifsFound" = "No GIFs Found";
"Gif.NoGifsPlaceholder" = "You have no saved GIFs yet.";
"Privacy.ProfilePhoto" = "Profile Photo";
"Privacy.Forwards" = "Forwarded Messages";
"Privacy.ProfilePhoto.WhoCanSeeMyPhoto" = "WHO CAN SEE MY PROFILE PHOTO";
"Privacy.ProfilePhoto.CustomHelp" = "You can restrict who can see your profile photo with granular precision.";
"Privacy.ProfilePhoto.AlwaysShareWith.Title" = "Always Share With";
"Privacy.ProfilePhoto.NeverShareWith.Title" = "Never Share With";
"Privacy.Forwards.WhoCanForward" = "WHO CAN ADD LINK TO MY ACCOUNT WHEN FORWARDING MY MESSAGES";
"Privacy.Forwards.CustomHelp" = "When forwarded to other chats, messages you send will not link back to your account.";
"Privacy.Forwards.AlwaysAllow.Title" = "Always Allow";
"Privacy.Forwards.NeverAllow.Title" = "Never Allow";
"Conversation.ContextMenuCancelSending" = "Cancel Sending";
"Conversation.ForwardAuthorHiddenTooltip" = "The account was hidden by the user";
"Privacy.Forwards.Preview" = "PREVIEW";
"Privacy.Forwards.PreviewMessageText" = "Reinhardt, we need to find you some new music.";
"Privacy.Forwards.AlwaysLink" = "Link to your account";
"Privacy.Forwards.LinkIfAllowed" = "Link if allowed by settings below";
"Privacy.Forwards.NeverLink" = "Not a link to your account";
"Chat.UnsendMyMessagesAlertTitle" = "Unsending will also delete messages you sent on %@'s side.";
"Chat.UnsendMyMessages" = "Unsend My Messages";
"Chat.DeleteMessagesConfirmation_1" = "Delete message";
"Chat.DeleteMessagesConfirmation_any" = "Delete %@ messages";
"Settings.Search" = "Search";
"SettingsSearch.FAQ" = "FAQ";
"SettingsSearch.Synonyms.EditProfile.Title" = " ";
"SettingsSearch.Synonyms.EditProfile.Bio" = " ";
"SettingsSearch.Synonyms.EditProfile.PhoneNumber" = " ";
"SettingsSearch.Synonyms.EditProfile.Username" = " ";
"SettingsSearch.Synonyms.EditProfile.AddAccount" = " ";
"SettingsSearch.Synonyms.EditProfile.Logout" = " ";
"SettingsSearch.Synonyms.Calls.Title" = " ";
"SettingsSearch.Synonyms.Calls.CallTab" = " ";
"SettingsSearch.Synonyms.Stickers.Title" = " ";
"SettingsSearch.Synonyms.Stickers.SuggestStickers" = " ";
"SettingsSearch.Synonyms.Stickers.FeaturedPacks" = " ";
"SettingsSearch.Synonyms.Stickers.ArchivedPacks" = " ";
"SettingsSearch.Synonyms.Stickers.Masks" = " ";
"SettingsSearch.Synonyms.Notifications.Title" = " ";
"SettingsSearch.Synonyms.Notifications.MessageNotificationsAlert" = " ";
"SettingsSearch.Synonyms.Notifications.MessageNotificationsPreview" = " ";
"SettingsSearch.Synonyms.Notifications.MessageNotificationsSound" = " ";
"SettingsSearch.Synonyms.Notifications.MessageNotificationsExceptions" = " ";
"SettingsSearch.Synonyms.Notifications.GroupNotificationsAlert" = " ";
"SettingsSearch.Synonyms.Notifications.GroupNotificationsPreview" = " ";
"SettingsSearch.Synonyms.Notifications.GroupNotificationsSound" = " ";
"SettingsSearch.Synonyms.Notifications.GroupNotificationsExceptions" = " ";
"SettingsSearch.Synonyms.Notifications.ChannelNotificationsAlert" = " ";
"SettingsSearch.Synonyms.Notifications.ChannelNotificationsPreview" = " ";
"SettingsSearch.Synonyms.Notifications.ChannelNotificationsSound" = " ";
"SettingsSearch.Synonyms.Notifications.ChannelNotificationsExceptions" = " ";
"SettingsSearch.Synonyms.Notifications.InAppNotificationsSound" = " ";
"SettingsSearch.Synonyms.Notifications.InAppNotificationsVibrate" = " ";
"SettingsSearch.Synonyms.Notifications.InAppNotificationsPreview" = " ";
"SettingsSearch.Synonyms.Notifications.DisplayNamesOnLockScreen" = " ";
"SettingsSearch.Synonyms.Notifications.BadgeIncludeMutedChats" = " ";
"SettingsSearch.Synonyms.Notifications.BadgeIncludeMutedPublicGroups" = " ";
"SettingsSearch.Synonyms.Notifications.BadgeIncludeMutedChannels" = " ";
"SettingsSearch.Synonyms.Notifications.BadgeCountUnreadMessages" = " ";
"SettingsSearch.Synonyms.Notifications.ContactJoined" = " ";
"SettingsSearch.Synonyms.Notifications.ResetAllNotifications" = " ";
"SettingsSearch.Synonyms.Privacy.Title" = " ";
"SettingsSearch.Synonyms.Privacy.BlockedUsers" = " ";
"SettingsSearch.Synonyms.Privacy.LastSeen" = " ";
"SettingsSearch.Synonyms.Privacy.ProfilePhoto" = " ";
"SettingsSearch.Synonyms.Privacy.Forwards" = " ";
"SettingsSearch.Synonyms.Privacy.Calls" = " ";
"SettingsSearch.Synonyms.Privacy.GroupsAndChannels" = " ";
"SettingsSearch.Synonyms.Privacy.Passcode" = " ";
"SettingsSearch.Synonyms.Privacy.PasscodeAndTouchId" = " ";
"SettingsSearch.Synonyms.Privacy.PasscodeAndFaceId" = " ";
"SettingsSearch.Synonyms.Privacy.TwoStepAuth" = "Password";
"SettingsSearch.Synonyms.Privacy.AuthSessions" = " ";
"SettingsSearch.Synonyms.Privacy.DeleteAccountIfAwayFor" = " ";
"SettingsSearch.Synonyms.Privacy.Data.Title" = " ";
"SettingsSearch.Synonyms.Privacy.Data.ContactsReset" = " ";
"SettingsSearch.Synonyms.Privacy.Data.ContactsSync" = " ";
"SettingsSearch.Synonyms.Privacy.Data.TopPeers" = " ";
"SettingsSearch.Synonyms.Privacy.Data.DeleteDrafts" = " ";
"SettingsSearch.Synonyms.Privacy.Data.ClearPaymentsInfo" = " ";
"SettingsSearch.Synonyms.Privacy.Data.SecretChatLinkPreview" = " ";
"SettingsSearch.Synonyms.Data.Title" = " ";
"SettingsSearch.Synonyms.Data.Storage.Title" = "Cache";
"SettingsSearch.Synonyms.Data.Storage.KeepMedia" = " ";
"SettingsSearch.Synonyms.Data.Storage.ClearCache" = " ";
"SettingsSearch.Synonyms.Data.NetworkUsage" = " ";
"SettingsSearch.Synonyms.Data.AutoDownloadUsingCellular" = " ";
"SettingsSearch.Synonyms.Data.AutoDownloadUsingWifi" = " ";
"SettingsSearch.Synonyms.Data.AutoDownloadReset" = " ";
"SettingsSearch.Synonyms.Data.AutoplayGifs" = " ";
"SettingsSearch.Synonyms.Data.AutoplayVideos" = " ";
"SettingsSearch.Synonyms.Data.CallsUseLessData" = " ";
"SettingsSearch.Synonyms.Data.SaveIncomingPhotos" = " ";
"SettingsSearch.Synonyms.Data.SaveEditedPhotos" = " ";
"SettingsSearch.Synonyms.Data.DownloadInBackground" = " ";
"SettingsSearch.Synonyms.Proxy.Title" = "SOCKS5\nMTProto";
"SettingsSearch.Synonyms.Proxy.AddProxy" = " ";
"SettingsSearch.Synonyms.Proxy.UseForCalls" = " ";
"SettingsSearch.Synonyms.Appearance.Title" = " ";
"SettingsSearch.Synonyms.Appearance.TextSize" = " ";
"SettingsSearch.Synonyms.Appearance.ChatBackground" = "Wallpaper";
"SettingsSearch.Synonyms.Appearance.ChatBackground.SetColor" = " ";
"SettingsSearch.Synonyms.Appearance.ChatBackground.Custom" = " ";
"SettingsSearch.Synonyms.Appearance.AutoNightTheme" = " ";
"SettingsSearch.Synonyms.Appearance.ColorTheme" = " ";
"SettingsSearch.Synonyms.Appearance.Animations" = "Animations";
"SettingsSearch.Synonyms.SavedMessages" = " ";
"SettingsSearch.Synonyms.AppLanguage" = " ";
"SettingsSearch.Synonyms.Passport" = " ";
"SettingsSearch.Synonyms.Watch" = "Apple Watch";
"SettingsSearch.Synonyms.Support" = "Support";
"SettingsSearch.Synonyms.FAQ" = " ";
"ChatList.DeleteForCurrentUser" = "Delete just for me";
"ChatList.DeleteForEveryone" = "Delete for me and %@";
"ChatList.ClearChatConfirmation" = "Are you sure you want to delete all\nmessages in the chat with %@?";