Support for updated accounts API

Implemented Notification Service Extension
This commit is contained in:
Peter Iakovlev 2019-01-29 14:04:17 +04:00
parent 70ebab5a68
commit d0d8f7dcd4
27 changed files with 1342 additions and 351 deletions

View file

@ -11,7 +11,7 @@ private enum NotificationContentAuthorizationError {
case unauthorized
}
private var accountCache: (Account, AccountManager)?
private var sharedAccountContext: SharedAccountContext?
private var installedSharedLogger = false
@ -22,9 +22,27 @@ private func setupSharedLogger(_ path: String) {
}
}
private func parseFileLocationResource(_ dict: [AnyHashable: Any]) -> TelegramMediaResource? {
guard let datacenterId = dict["datacenterId"] as? Int32 else {
return nil
}
guard let volumeId = dict["volumeId"] as? Int64 else {
return nil
}
guard let localId = dict["localId"] as? Int32 else {
return nil
}
guard let secret = dict["secret"] as? Int64 else {
return nil
}
var fileReference: Data?
if let fileReferenceString = dict["fileReference"] as? String {
fileReference = dataWithHexString(fileReferenceString)
}
return CloudFileMediaResource(datacenterId: Int(datacenterId), volumeId: volumeId, localId: localId, secret: secret, size: nil, fileReference: fileReference)
}
class NotificationViewController: UIViewController, UNNotificationContentExtension {
private let accountPromise = Promise<Account>()
private let imageNode = TransformImageNode()
private var imageDimensions: CGSize?
@ -66,47 +84,37 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
setupSharedLogger(logsPath)
let account: Signal<(Account, AccountManager), NotificationContentAuthorizationError>
if let accountCache = accountCache {
account = .single(accountCache)
} else {
if sharedAccountContext == nil {
initializeAccountManagement()
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
let applicationBindings = TelegramApplicationBindings(isMainApp: false, containerPath: appGroupUrl.path, appSpecificScheme: BuildConfig.shared().appSpecificUrlScheme, openUrl: { _ in
}, openUniversalUrl: { _, completion in
completion.completion(false)
return
}, canOpenUrl: { _ in
return false
}, getTopWindow: {
return nil
}, displayNotification: { _ in
}, applicationInForeground: .single(false), applicationIsActive: .single(false), clearMessageNotifications: { _ in
}, pushIdleTimerExtension: {
return EmptyDisposable
}, openSettings: {}, openAppStorePage: {}, registerForNotifications: { _ in }, requestSiriAuthorization: { _ in }, siriAuthorization: { return .notDetermined }, getWindowHost: {
return nil
}, presentNativeController: { _ in
}, dismissNativeController: {
})
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement()
account = accountManager(basePath: rootPath + "/accounts-metadata")
|> take(1)
|> introduceError(NotificationContentAuthorizationError.self)
|> mapToSignal { accountManager -> Signal<(Account, AccountManager), NotificationContentAuthorizationError> in
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: telegramAccountAuxiliaryMethods)
|> introduceError(NotificationContentAuthorizationError.self)
|> mapToSignal { account -> Signal<(Account, AccountManager), NotificationContentAuthorizationError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
setupAccount(account)
accountCache = (account, accountManager)
return .single((account, accountManager))
case .unauthorized:
return .fail(.unauthorized)
}
} else {
return .complete()
}
}
}
|> take(1)
sharedAccountContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
}
self.accountPromise.set(account
|> map { $0.0 }
|> `catch` { _ -> Signal<Account, NoError> in
return .complete()
})
}
func didReceive(_ notification: UNNotification) {
if let peerIdValue = notification.request.content.userInfo["peerId"] as? Int64, let messageIdNamespace = notification.request.content.userInfo["messageId.namespace"] as? Int32, let messageIdId = notification.request.content.userInfo["messageId.id"] as? Int32, let dict = notification.request.content.userInfo["mediaInfo"] as? [String: Any] {
if let accountIdValue = notification.request.content.userInfo["accountId"] as? Int64, let peerIdValue = notification.request.content.userInfo["peerId"] as? Int64, let messageIdNamespace = notification.request.content.userInfo["messageId.namespace"] as? Int32, let messageIdId = notification.request.content.userInfo["messageId.id"] as? Int32, let dict = notification.request.content.userInfo["mediaInfo"] as? [String: Any] {
let messageId = MessageId(peerId: PeerId(peerIdValue), namespace: messageIdNamespace, id: messageIdId)
if let imageInfo = dict["image"] as? [String: Any] {
@ -139,19 +147,36 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
|> map { $0.1 })
}
self.applyDisposable.set((self.accountPromise.get()
guard let sharedAccountContext = sharedAccountContext else {
return
}
self.applyDisposable.set((sharedAccountContext.activeAccounts
|> map { _, accounts, _ -> Account? in
return accounts[AccountRecordId(rawValue: accountIdValue)]
}
|> filter { account in
return account != nil
}
|> take(1)
|> mapToSignal { account -> Signal<(Account, ImageMediaReference?), NoError> in
guard let account = account else {
return .complete()
}
return account.postbox.messageAtId(messageId)
|> take(1)
|> map { message in
var imageReference: ImageMediaReference?
if let message = message {
if let message = message, false {
for media in message.media {
if let image = media as? TelegramMediaImage {
imageReference = .message(message: MessageReference(message), media: image)
}
}
} else {
if let thumbnailFileLocation = thumbnailInfo["fileLocation"] as? [AnyHashable: Any], let thumbnailResource = parseFileLocationResource(thumbnailFileLocation), let fileLocation = fullSizeInfo["fileLocation"] as? [AnyHashable: Any], let resource = parseFileLocationResource(fileLocation) {
imageReference = .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: 1), representations: [TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(width), height: CGFloat(height)).fitted(CGSize(width: 320.0, height: 320.0)), resource: thumbnailResource), TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(width), height: CGFloat(height)), resource: resource)], immediateThumbnailData: nil, reference: nil, partialReference: nil))
}
}
return (account, imageReference)
}

View file

@ -0,0 +1,118 @@
import Foundation
import CommonCrypto
struct MasterNotificationKey: Codable {
let id: Data
let data: Data
}
struct AccountDatacenterKey: Codable {
let id: Int64
let data: Data
}
struct AccountDatacenterInfo: Codable {
let masterKey: AccountDatacenterKey
}
struct StoredAccountInfo: Codable {
let primaryId: Int32
let isTestingEnvironment: Bool
let datacenters: [Int32: AccountDatacenterInfo]
}
struct AccountData {
let id: Int64
let isTestingEnvironment: Bool
let basePath: String
let datacenterId: Int32
let datacenters: [Int32: AccountDatacenterInfo]
let notificationKey: MasterNotificationKey?
}
func loadAccountsData(rootPath: String) -> [Int64: AccountData] {
var result: [Int64: AccountData] = [:]
if let contents = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath), includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) {
for url in contents {
let directoryName = url.lastPathComponent
if directoryName.hasPrefix("account-"), let id = UInt64(directoryName[directoryName.index(directoryName.startIndex, offsetBy: "account-".count)...]) {
var notificationKey: MasterNotificationKey?
if let data = try? Data(contentsOf: URL(fileURLWithPath: url.path + "/notificationsKey")), let value = try? JSONDecoder().decode(MasterNotificationKey.self, from: data) {
notificationKey = value
}
var storedInfo: StoredAccountInfo?
if let data = try? Data(contentsOf: URL(fileURLWithPath: url.path + "/storedInfo")), let value = try? JSONDecoder().decode(StoredAccountInfo.self, from: data) {
storedInfo = value
}
if let storedInfo = storedInfo {
result[Int64(bitPattern: id)] = AccountData(id: Int64(bitPattern: id), isTestingEnvironment: storedInfo.isTestingEnvironment, basePath: url.path, datacenterId: storedInfo.primaryId, datacenters: storedInfo.datacenters, notificationKey: notificationKey)
}
}
}
}
return result
}
private func sha256Digest(_ data: Data) -> Data {
let length = data.count
return data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Data in
var result = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
result.withUnsafeMutableBytes { (destBytes: UnsafeMutablePointer<UInt8>) -> Void in
CC_SHA256(bytes, UInt32(length), destBytes)
}
return result
}
}
func decryptedNotificationPayload(accounts: [Int64: AccountData], data: Data) -> (AccountData, [AnyHashable: Any])? {
if data.count < 8 + 16 {
return nil
}
for (_, account) in accounts {
guard let notificationKey = account.notificationKey else {
continue
}
if data.subdata(in: 0 ..< 8) != notificationKey.id {
continue
}
let x = 8
let msgKey = data.subdata(in: 8 ..< (8 + 16))
let rawData = data.subdata(in: (8 + 16) ..< data.count)
let sha256_a = sha256Digest(msgKey + notificationKey.data.subdata(in: x ..< (x + 36)))
let sha256_b = sha256Digest(notificationKey.data.subdata(in: (40 + x) ..< (40 + x + 36)) + msgKey)
let aesKey = sha256_a.subdata(in: 0 ..< 8) + sha256_b.subdata(in: 8 ..< (8 + 16)) + sha256_a.subdata(in: 24 ..< (24 + 8))
let aesIv = sha256_b.subdata(in: 0 ..< 8) + sha256_a.subdata(in: 8 ..< (8 + 16)) + sha256_b.subdata(in: 24 ..< (24 + 8))
guard let data = MTAesDecrypt(rawData, aesKey, aesIv), data.count > 4 else {
return nil
}
var dataLength: Int32 = 0
data.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Void in
memcpy(&dataLength, bytes, 4)
}
if dataLength < 0 || dataLength > data.count - 4 {
return nil
}
let checkMsgKeyLarge = sha256Digest(notificationKey.data.subdata(in: (88 + x) ..< (88 + x + 32)) + data)
let checkMsgKey = checkMsgKeyLarge.subdata(in: 8 ..< (8 + 16))
if checkMsgKey != msgKey {
return nil
}
let contentData = data.subdata(in: 4 ..< (4 + Int(dataLength)))
guard let result = try? JSONSerialization.jsonObject(with: contentData, options: []) else {
return nil
}
guard let dict = result as? [AnyHashable: Any] else {
return nil
}
return (account, dict)
}
return nil
}

View file

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv);
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,73 @@
#import "Crypto.h"
#import <CommonCrypto/CommonCrypto.h>
#define AES_BLOCK_SIZE 16
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
typedef struct {
unsigned long data[N_WORDS];
} aes_block_t;
static void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
unsigned char aesIv[AES_BLOCK_SIZE];
memcpy(aesIv, iv, AES_BLOCK_SIZE);
unsigned char ccIv[AES_BLOCK_SIZE];
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
0);
CCCryptorRef decryptor = NULL;
CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &decryptor);
if (decryptor != NULL) {
int len;
size_t n;
len = length / AES_BLOCK_SIZE;
aes_block_t *ivp = (aes_block_t *)(aesIv);
aes_block_t *iv2p = (aes_block_t *)(ccIv);
while (len) {
aes_block_t tmp;
aes_block_t *inp = (aes_block_t *)inBytes;
aes_block_t *outp = (aes_block_t *)outBytes;
for (n = 0; n < N_WORDS; ++n)
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
size_t dataOutMoved = 0;
CCCryptorStatus result = CCCryptorUpdate(decryptor, &tmp, AES_BLOCK_SIZE, outBytes, AES_BLOCK_SIZE, &dataOutMoved);
assert(result == kCCSuccess);
assert(dataOutMoved == AES_BLOCK_SIZE);
for (n = 0; n < N_WORDS; ++n)
outp->data[n] ^= ivp->data[n];
ivp = inp;
iv2p = outp;
inBytes += AES_BLOCK_SIZE;
outBytes += AES_BLOCK_SIZE;
--len;
}
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
CCCryptorRelease(decryptor);
}
}
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv) {
assert(key != nil && iv != nil);
NSMutableData *resultData = [[NSMutableData alloc] initWithLength:data.length];
unsigned char aesIv[16 * 2];
memcpy(aesIv, iv.bytes, iv.length);
MyAesIgeDecrypt(data.bytes, (int)data.length, resultData.mutableBytes, key.bytes, (int)key.length, aesIv);
return resultData;
}

View file

@ -0,0 +1,31 @@
import Foundation
enum Namespaces {
struct Peer {
static let CloudUser: PeerId.Namespace = 0
static let CloudGroup: PeerId.Namespace = 1
static let CloudChannel: PeerId.Namespace = 2
}
}
struct PeerId {
typealias Namespace = Int32
typealias Id = Int32
public let namespace: Namespace
public let id: Id
public init(namespace: Namespace, id: Id) {
self.namespace = namespace
self.id = id
}
public init(_ n: Int64) {
self.namespace = Int32((n >> 32) & 0x7fffffff)
self.id = Int32(bitPattern: UInt32(n & 0xffffffff))
}
public func toInt64() -> Int64 {
return (Int64(self.namespace) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: self.id)))
}
}

View file

@ -0,0 +1,421 @@
import Foundation
import MtProtoKitDynamic
struct ImageResource {
let datacenterId: Int
let volumeId: Int64
let localId: Int32
let secret: Int64
let fileReference: Data?
var resourceId: String {
return "telegram-cloud-file-\(self.datacenterId)-\(self.volumeId)-\(self.localId)-\(self.secret)"
}
}
private final class Buffer {
var data: UnsafeMutableRawPointer?
var _size: UInt = 0
private var capacity: UInt = 0
private let freeWhenDone: Bool
var size: Int {
return Int(self._size)
}
deinit {
if self.freeWhenDone {
free(self.data)
}
}
init(memory: UnsafeMutableRawPointer?, size: Int, capacity: Int, freeWhenDone: Bool) {
self.data = memory
self._size = UInt(size)
self.capacity = UInt(capacity)
self.freeWhenDone = freeWhenDone
}
init() {
self.data = nil
self._size = 0
self.capacity = 0
self.freeWhenDone = true
}
convenience init(data: Data?) {
self.init()
if let data = data {
data.withUnsafeBytes { bytes in
self.appendBytes(bytes, length: UInt(data.count))
}
}
}
func makeData() -> Data {
return self.withUnsafeMutablePointer { pointer, size -> Data in
if let pointer = pointer {
return Data(bytes: pointer.assumingMemoryBound(to: UInt8.self), count: Int(size))
} else {
return Data()
}
}
}
var description: String {
get {
var string = ""
if let data = self.data {
var i: UInt = 0
let bytes = data.assumingMemoryBound(to: UInt8.self)
while i < _size && i < 8 {
string += String(format: "%02x", Int(bytes.advanced(by: Int(i)).pointee))
i += 1
}
if i < _size {
string += "...\(_size)b"
}
} else {
string += "<null>"
}
return string
}
}
func appendBytes(_ bytes: UnsafeRawPointer, length: UInt) {
if self.capacity < self._size + length {
self.capacity = self._size + length + 128
if self.data == nil {
self.data = malloc(Int(self.capacity))!
}
else {
self.data = realloc(self.data, Int(self.capacity))!
}
}
memcpy(self.data?.advanced(by: Int(self._size)), bytes, Int(length))
self._size += length
}
func appendBuffer(_ buffer: Buffer) {
if self.capacity < self._size + buffer._size {
self.capacity = self._size + buffer._size + 128
if self.data == nil {
self.data = malloc(Int(self.capacity))!
}
else {
self.data = realloc(self.data, Int(self.capacity))!
}
}
memcpy(self.data?.advanced(by: Int(self._size)), buffer.data, Int(buffer._size))
}
func appendInt32(_ value: Int32) {
var v = value
self.appendBytes(&v, length: 4)
}
func appendInt64(_ value: Int64) {
var v = value
self.appendBytes(&v, length: 8)
}
func appendDouble(_ value: Double) {
var v = value
self.appendBytes(&v, length: 8)
}
func withUnsafeMutablePointer<R>(_ f: (UnsafeMutableRawPointer?, UInt) -> R) -> R {
return f(self.data, self._size)
}
}
private class BufferReader {
private let buffer: Buffer
private(set) var offset: UInt = 0
init(_ buffer: Buffer) {
self.buffer = buffer
}
func reset() {
self.offset = 0
}
func skip(_ count: Int) {
self.offset = min(self.buffer._size, self.offset + UInt(count))
}
func readInt32() -> Int32? {
if self.offset + 4 <= self.buffer._size {
let value: Int32 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int32.self).pointee
self.offset += 4
return value
}
return nil
}
func readInt64() -> Int64? {
if self.offset + 8 <= self.buffer._size {
let value: Int64 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int64.self).pointee
self.offset += 8
return value
}
return nil
}
func readDouble() -> Double? {
if self.offset + 8 <= self.buffer._size {
let value: Double = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Double.self).pointee
self.offset += 8
return value
}
return nil
}
func readBytesAsInt32(_ count: Int) -> Int32? {
if count == 0 {
return 0
}
else if count > 0 && count <= 4 || self.offset + UInt(count) <= self.buffer._size {
var value: Int32 = 0
memcpy(&value, self.buffer.data?.advanced(by: Int(self.offset)), count)
self.offset += UInt(count)
return value
}
return nil
}
func readBuffer(_ count: Int) -> Buffer? {
if count >= 0 && self.offset + UInt(count) <= self.buffer._size {
let buffer = Buffer()
buffer.appendBytes((self.buffer.data?.advanced(by: Int(self.offset)))!, length: UInt(count))
self.offset += UInt(count)
return buffer
}
return nil
}
}
private func serializeBytes(_ value: Buffer, buffer: Buffer, boxed: Bool) {
if boxed {
buffer.appendInt32(-1255641564)
}
var length: Int32 = Int32(value.size)
var padding: Int32 = 0
if (length >= 254)
{
var tmp: UInt8 = 254
buffer.appendBytes(&tmp, length: 1)
buffer.appendBytes(&length, length: 3)
padding = (((length % 4) == 0 ? length : (length + 4 - (length % 4)))) - length;
}
else
{
buffer.appendBytes(&length, length: 1)
let e1 = (((length + 1) % 4) == 0 ? (length + 1) : ((length + 1) + 4 - ((length + 1) % 4)))
padding = (e1) - (length + 1)
}
if value.size != 0 {
buffer.appendBytes(value.data!, length: UInt(length))
}
var i: Int32 = 0
var tmp: UInt8 = 0
while i < padding {
buffer.appendBytes(&tmp, length: 1)
i += 1
}
}
private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
if multiple == 0 {
return numToRound
}
let remainder = numToRound % multiple
if remainder == 0 {
return numToRound
}
return numToRound + multiple - remainder
}
private func parseBytes(_ reader: BufferReader) -> Buffer? {
if let tmp = reader.readBytesAsInt32(1) {
var paddingBytes: Int = 0
var length: Int = 0
if tmp == 254 {
if let len = reader.readBytesAsInt32(3) {
length = Int(len)
paddingBytes = roundUp(length, multiple: 4) - length
}
else {
return nil
}
}
else {
length = Int(tmp)
paddingBytes = roundUp(length + 1, multiple: 4) - (length + 1)
}
let buffer = reader.readBuffer(length)
reader.skip(paddingBytes)
return buffer
}
return nil
}
private class Keychain: NSObject, MTKeychain {
var dict: [String: Data] = [:]
func setObject(_ object: Any!, forKey aKey: String!, group: String!) {
let data = NSKeyedArchiver.archivedData(withRootObject: object)
self.dict[group + ":" + aKey] = data
}
func object(forKey aKey: String!, group: String!) -> Any! {
if let data = self.dict[group + ":" + aKey] {
return NSKeyedUnarchiver.unarchiveObject(with: data as Data)
}
return nil
}
func removeObject(forKey aKey: String!, group: String!) {
self.dict.removeValue(forKey: group + ":" + aKey)
}
func dropGroup(_ group: String!) {
}
}
private final class ParsedFile: NSObject {
let data: Data?
init(data: Data?) {
self.data = data
super.init()
}
}
func fetchImageWithAccount(account: AccountData, resource: ImageResource, completion: @escaping (Data?) -> Void) -> () -> Void {
MTLogSetEnabled(true)
MTLogSetLoggingFunction({ str, args in
//let string = NSString(format: str! as NSString, args!)
print("MT: \(str!)")
})
let serialization = Serialization()
var apiEnvironment = MTApiEnvironment()
apiEnvironment.apiId = BuildConfig.shared().apiId
apiEnvironment.langPack = "ios"
apiEnvironment.layer = NSNumber(value: Int(serialization.currentLayer()))
apiEnvironment.disableUpdates = true
apiEnvironment = apiEnvironment.withUpdatedLangPackCode("en")
let context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: account.isTestingEnvironment, useTempAuthKeys: false)!
let seedAddressList: [Int: [String]]
if account.isTestingEnvironment {
seedAddressList = [
1: ["149.154.175.10"],
2: ["149.154.167.40"]
]
} else {
seedAddressList = [
1: ["149.154.175.50", "2001:b28:f23d:f001::a"],
2: ["149.154.167.50", "2001:67c:4e8:f002::a"],
3: ["149.154.175.100", "2001:b28:f23d:f003::a"],
4: ["149.154.167.91", "2001:67c:4e8:f004::a"],
5: ["149.154.171.5", "2001:b28:f23f:f005::a"]
]
}
for (id, ips) in seedAddressList {
context.setSeedAddressSetForDatacenterWithId(id, seedAddressSet: MTDatacenterAddressSet(addressList: ips.map { MTDatacenterAddress(ip: $0, port: 443, preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: nil) }))
}
let keychain = Keychain()
context.keychain = keychain
for (id, info) in account.datacenters {
context.updateAuthInfoForDatacenter(withId: Int(id), authInfo: MTDatacenterAuthInfo(authKey: info.masterKey.data, authKeyId: info.masterKey.id, saltSet: [], authKeyAttributes: [:], mainTempAuthKey: nil, mediaTempAuthKey: nil))
}
let mtProto = MTProto(context: context, datacenterId: resource.datacenterId, usageCalculationInfo: nil)!
mtProto.useTempAuthKeys = context.useTempAuthKeys
mtProto.checkForProxyConnectionIssues = false
let requestService = MTRequestMessageService(context: context)!
mtProto.add(requestService)
let request = MTRequest()
let buffer = Buffer()
buffer.appendInt32(-475607115) //upload.getFile
buffer.appendInt32(-539317279) //InputFileLocation.inputFileLocation
buffer.appendInt64(resource.volumeId)
buffer.appendInt32(resource.localId)
buffer.appendInt64(resource.secret)
serializeBytes(Buffer(data: resource.fileReference), buffer: buffer, boxed: false)
buffer.appendInt32(0)
buffer.appendInt32(32 * 1024)
request.setPayload(buffer.makeData(), metadata: "getFile", responseParser: { response in
let reader = BufferReader(Buffer(data: response))
guard let signature = reader.readInt32() else {
return ParsedFile(data: nil)
}
guard signature == 157948117 else {
return ParsedFile(data: nil)
}
reader.skip(4) //type
reader.skip(4) //mtime
guard let bytes = parseBytes(reader) else {
return ParsedFile(data: nil)
}
return ParsedFile(data: bytes.makeData())
})
request.dependsOnPasswordEntry = false
request.shouldContinueExecutionWithErrorContext = { errorContext in
guard let _ = errorContext else {
return true
}
return true
}
request.completed = { (boxedResponse, timestamp, error) -> () in
if let _ = error {
completion(nil)
} else {
if let result = boxedResponse as? ParsedFile {
completion(result.data)
} else {
completion(nil)
}
}
}
requestService.add(request)
mtProto.resume()
let internalId = request.internalId
return {
requestService.removeRequest(byInternalId: internalId)
context.performBatchUpdates({})
mtProto.stop()
}
}

View file

@ -17,9 +17,9 @@
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>5.2</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>${BUILD_NUMBER}</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>

View file

@ -0,0 +1,7 @@
#ifndef NotificationService_BridgingHeader_h
#define NotificationService_BridgingHeader_h
#import "../Telegram-iOS/BuildConfig.h"
#import "Crypto.h"
#endif

View file

@ -1,26 +1,280 @@
import Foundation
import UserNotifications
private func dataWithHexString(_ string: String) -> Data {
var hex = string
if hex.count % 2 != 0 {
return Data()
}
var data = Data()
while hex.count > 0 {
let subIndex = hex.index(hex.startIndex, offsetBy: 2)
let c = String(hex[..<subIndex])
hex = String(hex[subIndex...])
var ch: UInt32 = 0
if !Scanner(string: c).scanHexInt32(&ch) {
return Data()
}
var char = UInt8(ch)
data.append(&char, count: 1)
}
return data
}
private func parseInt64(_ value: Any?) -> Int64? {
if let value = value as? String {
return Int64(value)
} else if let value = value as? Int64 {
return value
} else {
return nil
}
}
private func parseInt32(_ value: Any?) -> Int32? {
if let value = value as? String {
return Int32(value)
} else if let value = value as? Int32 {
return value
} else {
return nil
}
}
private func parseImageLocation(_ dict: [AnyHashable: Any]) -> (size: (width: Int32, height: Int32)?, resource: ImageResource)? {
guard let datacenterId = parseInt32(dict["dc_id"]) else {
return nil
}
guard let volumeId = parseInt64(dict["volume_id"]) else {
return nil
}
guard let localId = parseInt32(dict["local_id"]) else {
return nil
}
guard let secret = parseInt64(dict["secret"]) else {
return nil
}
var fileReference: Data?
if let fileReferenceString = dict["file_reference"] as? String {
fileReference = Data(base64Encoded: fileReferenceString)
}
var size: (Int32, Int32)?
if let width = parseInt32(dict["w"]), let height = parseInt32(dict["h"]) {
size = (width, height)
}
return (size, ImageResource(datacenterId: Int(datacenterId), volumeId: volumeId, localId: localId, secret: secret, fileReference: fileReference))
}
private func hexString(_ data: Data) -> String {
let hexString = NSMutableString()
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
for i in 0 ..< data.count {
hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee))
}
}
return hexString as String
}
private func serializeImageLocation(_ resource: ImageResource) -> [AnyHashable: Any] {
var result: [AnyHashable: Any] = [:]
result["datacenterId"] = Int32(resource.datacenterId)
result["volumeId"] = resource.volumeId
result["localId"] = resource.localId
result["secret"] = resource.secret
if let fileReference = resource.fileReference {
result["fileReference"] = hexString(fileReference)
}
return result
}
class NotificationService: UNNotificationServiceExtension {
private let rootPath: String?
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
var cancelFetch: (() -> Void)?
override init() {
let appBundleIdentifier = Bundle.main.bundleIdentifier!
if let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) {
let appGroupName = "group.\(appBundleIdentifier[..<lastDotRange.lowerBound])"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
if let appGroupUrl = maybeAppGroupUrl {
self.rootPath = appGroupUrl.path + "/telegram-data"
} else {
self.rootPath = nil
}
} else {
self.rootPath = nil
}
super.init()
}
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
let accountsData = self.rootPath.flatMap({ rootPath in
loadAccountsData(rootPath: rootPath)
}) ?? [:]
self.contentHandler = contentHandler
self.bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
if let bestAttemptContent = self.bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
contentHandler(bestAttemptContent)
var encryptedData: Data?
if var encryptedPayload = 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 (account, dict) = encryptedData.flatMap({ decryptedNotificationPayload(accounts: accountsData, data: $0) }) {
var userInfo = self.bestAttemptContent?.userInfo ?? [:]
userInfo["accountId"] = account.id
var peerId: PeerId?
var messageId: Int32?
if let msgId = dict["msg_id"] as? String {
userInfo["msg_id"] = msgId
messageId = Int32(msgId)
}
if let fromId = dict["from_id"] as? String {
userInfo["from_id"] = fromId
if let id = Int32(fromId) {
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
}
}
if let chatId = dict["chat_id"] as? String {
userInfo["chat_id"] = chatId
if let id = Int32(chatId) {
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: id)
}
}
if let channelId = dict["channel_id"] as? String {
userInfo["channel_id"] = channelId
if let id = Int32(channelId) {
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)
}
}
var thumbnailImage: ImageResource?
var fullSizeImage: (size: (width: Int32, height: Int32)?, resource: ImageResource)?
if let thumbLoc = dict["media_loc"] as? [AnyHashable: Any] {
thumbnailImage = (thumbLoc["thumb"] as? [AnyHashable: Any]).flatMap(parseImageLocation)?.resource
fullSizeImage = (thumbLoc["full"] as? [AnyHashable: Any]).flatMap(parseImageLocation)
}
let imagesPath = NSTemporaryDirectory() + "aps-data"
let _ = try? FileManager.default.createDirectory(atPath: imagesPath, withIntermediateDirectories: true, attributes: nil)
let mediaBoxPath = account.basePath + "/postbox/media"
let tempImagePath = thumbnailImage.flatMap({ imagesPath + "/\($0.resourceId).jpg" })
let mediaBoxThumbnailImagePath = thumbnailImage.flatMap({ mediaBoxPath + "/\($0.resourceId)" })
let mediaBoxFullSizeImagePath = fullSizeImage.flatMap({ mediaBoxPath + "/\($0.resource.resourceId)" })
if let aps = dict["aps"] as? [AnyHashable: Any] {
if let alert = aps["alert"] as? String {
self.bestAttemptContent?.title = ""
self.bestAttemptContent?.body = alert
} else if let alert = aps["alert"] as? [AnyHashable: Any] {
self.bestAttemptContent?.title = alert["title"] as? String ?? ""
self.bestAttemptContent?.subtitle = alert["subtitle"] as? String ?? ""
self.bestAttemptContent?.body = alert["body"] as? String ?? ""
}
if let threadId = aps["thread-id"] as? String {
self.bestAttemptContent?.threadIdentifier = threadId
}
if let sound = aps["sound"] as? String {
self.bestAttemptContent?.sound = UNNotificationSound(named: UNNotificationSoundName(sound))
}
if let category = aps["category"] as? String {
self.bestAttemptContent?.categoryIdentifier = category
if let peerId = peerId, let messageId = messageId, let thumbnailResource = thumbnailImage, let (maybeSize, resource) = fullSizeImage, let size = maybeSize {
userInfo["peerId"] = peerId.toInt64()
userInfo["messageId.namespace"] = 0 as Int32
userInfo["messageId.id"] = messageId
var imageInfo: [String: Any] = [:]
imageInfo["width"] = Int(size.width)
imageInfo["height"] = Int(size.height)
var thumbnail: [String: Any] = [:]
if let mediaBoxThumbnailImagePath = mediaBoxThumbnailImagePath {
thumbnail["path"] = mediaBoxThumbnailImagePath
}
thumbnail["fileLocation"] = serializeImageLocation(thumbnailResource)
var fullSize: [String: Any] = [:]
if let mediaBoxFullSizeImagePath = mediaBoxFullSizeImagePath {
fullSize["path"] = mediaBoxFullSizeImagePath
}
fullSize["fileLocation"] = serializeImageLocation(resource)
imageInfo["thumbnail"] = thumbnail
imageInfo["fullSize"] = fullSize
userInfo["mediaInfo"] = ["image": imageInfo]
if category == "r" {
self.bestAttemptContent?.categoryIdentifier = "withReplyMedia"
} else if category == "m" {
self.bestAttemptContent?.categoryIdentifier = "withMuteMedia"
}
}
}
}
self.bestAttemptContent?.userInfo = userInfo
self.cancelFetch?()
if let mediaBoxThumbnailImagePath = mediaBoxThumbnailImagePath, let tempImagePath = tempImagePath, let thumbnailImage = thumbnailImage {
self.cancelFetch = fetchImageWithAccount(account: account, resource: thumbnailImage, completion: { [weak self] data in
DispatchQueue.main.async {
guard let strongSelf = self else {
return
}
strongSelf.cancelFetch?()
strongSelf.cancelFetch = nil
if let data = data {
let _ = try? data.write(to: URL(fileURLWithPath: mediaBoxThumbnailImagePath))
if let _ = try? data.write(to: URL(fileURLWithPath: tempImagePath)) {
if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempImagePath)) {
strongSelf.bestAttemptContent?.attachments = [attachment]
}
}
}
if let bestAttemptContent = strongSelf.bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
})
} else {
if let bestAttemptContent = self.bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
} else {
if let bestAttemptContent = self.bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
self.cancelFetch?()
self.cancelFetch = nil
if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}

View file

@ -0,0 +1,42 @@
import Foundation
import MtProtoKitDynamic
public class BoxedMessage: NSObject {
public let body: Any
public init(_ body: Any) {
self.body = body
}
}
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 93
}
public func parseMessage(_ data: Data!) -> Any! {
return nil
}
public func exportAuthorization(_ datacenterId: Int32, data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTExportAuthorizationResponseParser!
{
return { data -> MTExportedAuthorizationData? in
return nil
}
}
public func importAuthorization(_ authId: Int32, bytes: Data!) -> Data! {
return Data()
}
public func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTRequestDatacenterAddressListParser! {
return { response -> MTDatacenterAddressListData? in
return nil
}
}
public func requestNoop(_ data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestNoopParser! {
return { response -> AnyObject? in
return nil
}
}
}

View file

@ -143,14 +143,11 @@ class ShareRootController: UIViewController {
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement()
account = accountManager(basePath: rootPath + "/accounts-metadata")
|> take(1)
|> mapToSignal { accountManager -> Signal<(SharedAccountContext, LoggingSettings), NoError> in
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
return accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
}
account = accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
}
|> introduceError(ShareAuthorizationError.self)
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContext, Account), ShareAuthorizationError> in
@ -181,19 +178,18 @@ class ShareRootController: UIViewController {
|> take(1)
}
let preferencesKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([ApplicationSpecificPreferencesKeys.presentationPasscodeSettings]))
let shouldBeMaster = self.shouldBeMaster
let applicationInterface = account
|> mapToSignal { sharedContext, account -> Signal<(AccountContext, PostboxAccessChallengeData), ShareAuthorizationError> in
return combineLatest(currentPresentationDataAndSettings(postbox: account.postbox), account.postbox.combinedView(keys: [.accessChallengeData, preferencesKey]) |> take(1))
return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox), sharedContext.accountManager.accessChallengeData())
|> take(1)
|> deliverOnMainQueue
|> introduceError(ShareAuthorizationError.self)
|> map { dataAndSettings, data -> (AccountContext, PostboxAccessChallengeData) in
|> map { sharedData, dataAndSettings, data -> (AccountContext, PostboxAccessChallengeData) in
accountCache = (sharedContext, account)
updateLegacyLocalization(strings: dataAndSettings.presentationData.strings)
let context = AccountContext(sharedContext: sharedContext, account: account, initialPresentationDataAndSettings: dataAndSettings)
return (context, (data.views[.accessChallengeData] as! AccessChallengeDataView).data)
return (context, data.data)
}
}
|> deliverOnMainQueue

View file

@ -82,32 +82,30 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
account = .single(accountCache)
} else {
initializeAccountManagement()
account = accountManager(basePath: rootPath + "/accounts-metadata")
|> take(1)
|> mapToSignal { accountManager -> Signal<Account, NoError> in
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods)
|> mapToSignal { account -> Signal<Account, NoError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
return applicationSettings(accountManager: accountManager)
|> deliverOnMainQueue
|> map { settings -> Account in
accountCache = account
Logger.shared.logToFile = settings.logging.logToFile
Logger.shared.logToConsole = settings.logging.logToConsole
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
return account
}
case .unauthorized:
return .complete()
}
} else {
return .complete()
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods)
|> mapToSignal { account -> Signal<Account, NoError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
return applicationSettings(accountManager: accountManager)
|> deliverOnMainQueue
|> map { settings -> Account in
accountCache = account
Logger.shared.logToFile = settings.logging.logToFile
Logger.shared.logToConsole = settings.logging.logToConsole
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
return account
}
case .unauthorized:
return .complete()
}
} else {
return .complete()
}
}
|> take(1)

View file

@ -213,7 +213,6 @@
09D304382174344900C00567 /* TGBridgeWebPageMediaAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 09C572F52172953500BDF00F /* TGBridgeWebPageMediaAttachment.m */; };
09D304392174344900C00567 /* TGBridgeMessageEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 09C572F42172953500BDF00F /* TGBridgeMessageEntities.m */; };
09FDAEE62140477F00BF856F /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09FDAEE52140477F00BF856F /* MtProtoKitDynamic.framework */; };
D000CACB21FB6E380011B15D /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000CACA21FB6E380011B15D /* NotificationService.swift */; };
D000CACF21FB6E380011B15D /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D000CAC821FB6E370011B15D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
D001D5AA1F878DA300DF975A /* PhoneCountries.txt in Resources */ = {isa = PBXBuildFile; fileRef = D001D5A91F878DA300DF975A /* PhoneCountries.txt */; };
D006CF9F21A8D11B00FDCD32 /* ModernProto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D006CF9E21A8D11B00FDCD32 /* ModernProto.framework */; };
@ -300,6 +299,8 @@
D06706611D51185400DED3E3 /* TelegramCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D06706601D51185400DED3E3 /* TelegramCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D06706621D5118F500DED3E3 /* TelegramCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706601D51185400DED3E3 /* TelegramCore.framework */; };
D06E4C2F21347D9200088087 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D06E4C2E21347D9200088087 /* UIImage+ImageEffects.m */; };
D073E52021FF7CE900742DDD /* Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = D073E51F21FF7CE900742DDD /* Crypto.m */; };
D073E52222003E1E00742DDD /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073E52122003E1E00742DDD /* Data.swift */; };
D084023220E1883500065674 /* ApplicationShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D084023120E1883500065674 /* ApplicationShortcutItem.swift */; };
D08410451FABDC5D008FFE92 /* TGItemProviderSignals.m in Sources */ = {isa = PBXBuildFile; fileRef = D08410441FABDC5C008FFE92 /* TGItemProviderSignals.m */; };
D08410481FABDCF2008FFE92 /* LegacyComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D08410491FABDCF2008FFE92 /* LegacyComponents.framework */; };
@ -419,6 +420,12 @@
D0ECCB7F1FE9C38500609802 /* Telegram_iOS_UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB7E1FE9C38500609802 /* Telegram_iOS_UITests.swift */; };
D0ECCB8A1FE9C4AC00609802 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB891FE9C4AC00609802 /* SnapshotHelper.swift */; };
D0ECCB8D1FE9CE3F00609802 /* SnapshotChatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB8C1FE9CE3F00609802 /* SnapshotChatList.swift */; };
D0ED633821FF3E1E001D4648 /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CAF2F21D75FFAB0011F558 /* MtProtoKitDynamic.framework */; };
D0ED633A21FF3EDF001D4648 /* AccountData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED633921FF3EDF001D4648 /* AccountData.swift */; };
D0ED633B21FF3EFD001D4648 /* BuildConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = D09250011FE52D2A003F693F /* BuildConfig.m */; };
D0ED633D21FF4580001D4648 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0400EE41D5B912E007931CE /* NotificationService.swift */; };
D0ED633F21FF46E4001D4648 /* ImageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED633E21FF46E4001D4648 /* ImageData.swift */; };
D0ED634121FF4786001D4648 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED634021FF4786001D4648 /* Serialization.swift */; };
D0F575132083B96B00F1C1E1 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0F575122083B96B00F1C1E1 /* CloudKit.framework */; };
D0FC1948201D2DA800FEDBB2 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = D0FC1947201D2DA700FEDBB2 /* SFCompactRounded-Semibold.otf */; };
/* End PBXBuildFile section */
@ -899,8 +906,6 @@
D000CAC221FB6E170011B15D /* NotificationService-AppStore.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NotificationService-AppStore.entitlements"; sourceTree = "<group>"; };
D000CAC321FB6E170011B15D /* NotificationService-AppStoreLLC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NotificationService-AppStoreLLC.entitlements"; sourceTree = "<group>"; };
D000CAC821FB6E370011B15D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
D000CACA21FB6E380011B15D /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
D000CACC21FB6E380011B15D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D001D5A91F878DA300DF975A /* PhoneCountries.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PhoneCountries.txt; path = "Telegram-iOS/Resources/PhoneCountries.txt"; sourceTree = "<group>"; };
D006CF9E21A8D11B00FDCD32 /* ModernProto.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ModernProto.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D006CFA121A8D12600FDCD32 /* ModernProto.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModernProto.framework; path = "../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-ffbqcdyqpehxdvcwhyaorlehrrdc/Build/Products/Debug Hockeyapp-iphoneos/ModernProto.framework"; sourceTree = "<group>"; };
@ -1031,6 +1036,9 @@
D06706601D51185400DED3E3 /* TelegramCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = TelegramCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D06E4C2D21347D9200088087 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ImageEffects.h"; sourceTree = "<group>"; };
D06E4C2E21347D9200088087 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ImageEffects.m"; sourceTree = "<group>"; };
D073E51E21FF7CE900742DDD /* Crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Crypto.h; sourceTree = "<group>"; };
D073E51F21FF7CE900742DDD /* Crypto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Crypto.m; sourceTree = "<group>"; };
D073E52122003E1E00742DDD /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
D079FD001F06BBD10038FADE /* Telegram-iOS-AppStore.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Telegram-iOS-AppStore.entitlements"; sourceTree = "<group>"; };
D079FD011F06BBD60038FADE /* Config-Hockeyapp.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Config-Hockeyapp.xcconfig"; sourceTree = "<group>"; };
D079FD021F06BBD60038FADE /* Config-AppStore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Config-AppStore.xcconfig"; sourceTree = "<group>"; };
@ -1166,6 +1174,10 @@
D0ECCB801FE9C38500609802 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D0ECCB891FE9C4AC00609802 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; };
D0ECCB8C1FE9CE3F00609802 /* SnapshotChatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotChatList.swift; sourceTree = "<group>"; };
D0ED633921FF3EDF001D4648 /* AccountData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountData.swift; sourceTree = "<group>"; };
D0ED633C21FF3F28001D4648 /* NotificationService-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NotificationService-Bridging-Header.h"; sourceTree = "<group>"; };
D0ED633E21FF46E4001D4648 /* ImageData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageData.swift; sourceTree = "<group>"; };
D0ED634021FF4786001D4648 /* Serialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = "<group>"; };
D0F575122083B96B00F1C1E1 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
D0FC1947201D2DA700FEDBB2 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "SFCompactRounded-Semibold.otf"; path = "Telegram-iOS/Resources/SFCompactRounded-Semibold.otf"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -1185,6 +1197,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D0ED633821FF3E1E001D4648 /* MtProtoKitDynamic.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1899,15 +1912,6 @@
name = Media;
sourceTree = "<group>";
};
D000CAC921FB6E380011B15D /* NotificationService */ = {
isa = PBXGroup;
children = (
D000CACA21FB6E380011B15D /* NotificationService.swift */,
D000CACC21FB6E380011B15D /* Info.plist */,
);
path = NotificationService;
sourceTree = "<group>";
};
D00859931B28189D00EAF753 = {
isa = PBXGroup;
children = (
@ -1919,7 +1923,6 @@
D0D268821D79A70A00C422DA /* SiriIntentsUI */,
D02CF5FF215D9ABF00E0F56A /* NotificationContent */,
09C56F8C2172797200BDF00F /* Watch */,
D000CAC921FB6E380011B15D /* NotificationService */,
D00859C21B281E0000EAF753 /* Frameworks */,
D008599E1B28189D00EAF753 /* Telegram-iOS */,
D0400EE31D5B912E007931CE /* NotificationService */,
@ -2151,7 +2154,14 @@
D000CAC121FB6E160011B15D /* NotificationService-Fork.entitlements */,
D000CAC021FB6E160011B15D /* NotificationService-HockeyApp.entitlements */,
D0400EE41D5B912E007931CE /* NotificationService.swift */,
D0ED633921FF3EDF001D4648 /* AccountData.swift */,
D0ED633E21FF46E4001D4648 /* ImageData.swift */,
D0400EE61D5B912E007931CE /* Info.plist */,
D0ED633C21FF3F28001D4648 /* NotificationService-Bridging-Header.h */,
D0ED634021FF4786001D4648 /* Serialization.swift */,
D073E51E21FF7CE900742DDD /* Crypto.h */,
D073E51F21FF7CE900742DDD /* Crypto.m */,
D073E52122003E1E00742DDD /* Data.swift */,
);
path = NotificationService;
sourceTree = "<group>";
@ -3172,7 +3182,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D000CACB21FB6E380011B15D /* NotificationService.swift in Sources */,
D073E52222003E1E00742DDD /* Data.swift in Sources */,
D0ED633B21FF3EFD001D4648 /* BuildConfig.m in Sources */,
D0ED633D21FF4580001D4648 /* NotificationService.swift in Sources */,
D0ED633A21FF3EDF001D4648 /* AccountData.swift in Sources */,
D0ED634121FF4786001D4648 /* Serialization.swift in Sources */,
D073E52021FF7CE900742DDD /* Crypto.m in Sources */,
D0ED633F21FF46E4001D4648 /* ImageData.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -4702,6 +4718,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -4765,6 +4782,7 @@
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -4775,6 +4793,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -4838,6 +4857,7 @@
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -4848,6 +4868,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -4911,6 +4932,7 @@
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -4921,6 +4943,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -4984,6 +5007,7 @@
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -4994,6 +5018,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -5049,6 +5074,7 @@
PROVISIONING_PROFILE_SPECIFIER = "match AppStore org.telegram.TelegramHD.NotificationService";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5060,6 +5086,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -5115,6 +5142,7 @@
PROVISIONING_PROFILE_SPECIFIER = "match AppStore ph.telegra.Telegraph.NotificationService";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5126,6 +5154,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -5181,6 +5210,7 @@
PROVISIONING_PROFILE_SPECIFIER = "match InHouse org.telegram.Telegram-iOS.NotificationService";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
@ -5192,6 +5222,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_NUMBER = 99999;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@ -5247,6 +5278,7 @@
PROVISIONING_PROFILE_SPECIFIER = "match InHouse org.telegram.Telegram-iOS.NotificationService";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";

View file

@ -57,7 +57,7 @@
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug Hockeyapp"
buildConfiguration = "DebugHockeyapp"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
@ -68,9 +68,9 @@
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<RemoteRunnable
runnableDebuggingMode = "0"
BundleIdentifier = "org.telegram.Telegram-iOS"
RemotePath = "/var/containers/Bundle/Application/40124EF3-F9E6-4274-8750-77DC100D9950/Telegram X.app">
runnableDebuggingMode = "1"
BundleIdentifier = "com.apple.mobilesafari"
RemotePath = "/Applications/MobileSafari.app">
</RemoteRunnable>
<MacroExpansion>
<BuildableReference

View file

@ -583,13 +583,12 @@ private enum QueuedWakeup: Int32 {
self.window?.rootViewController?.dismiss(animated: true, completion: nil)
})
self.sharedContextPromise.set(accountManager(basePath: rootPath + "/accounts-metadata")
|> deliverOnMainQueue
|> mapToSignal { accountManager -> Signal<(SharedAccountContext, LoggingSettings), NoError> in
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: networkArguments, rootPath: rootPath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init))
return accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
}
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: networkArguments, rootPath: rootPath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init))
self.sharedContextPromise.set(
accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
}
|> mapToSignal { sharedContext, loggingSettings -> Signal<SharedAccountContext, NoError> in
Logger.shared.logToFile = loggingSettings.logToFile
@ -686,12 +685,12 @@ private enum QueuedWakeup: Int32 {
})
|> mapToSignal { account, hasOther -> Signal<(AnyObject, InitialPresentationDataAndSettings, Bool)?, NoError> in
if let account = account as? Account {
return currentPresentationDataAndSettings(postbox: account.postbox)
return currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox)
|> map { initialSettings in
return (account, initialSettings, hasOther)
}
} else if let account = account as? UnauthorizedAccount {
return currentPresentationDataAndSettings(postbox: account.postbox)
return currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox)
|> map { initialSettings in
return (account, initialSettings, hasOther)
}
@ -1314,14 +1313,6 @@ private enum QueuedWakeup: Int32 {
private func openUrl(url: URL) {
let _ = (self.context.get()
|> flatMap { $0 }
|> filter { context in
switch context {
case .authorized, .unauthorized:
return true
default:
return false
}
}
|> take(1)
|> deliverOnMainQueue).start(next: { contextValue in
switch contextValue {
@ -1331,7 +1322,7 @@ private enum QueuedWakeup: Int32 {
if let proxyData = parseProxyUrl(url) {
context.rootController.view.endEditing(true)
let strings = context.strings
let controller = ProxyServerActionSheetController(theme: defaultPresentationTheme, strings: strings, postbox: context.account.postbox, network: context.account.network, server: proxyData, presentationData: nil)
let controller = ProxyServerActionSheetController(theme: defaultPresentationTheme, strings: strings, accountManager: context.sharedContext.accountManager, postbox: context.account.postbox, network: context.account.network, server: proxyData, presentationData: nil)
context.rootController.currentWindow?.present(controller, on: PresentationSurfaceLevel.root, blockInteraction: false, completion: {})
} else if let secureIdData = parseSecureIdUrl(url) {
let strings = context.strings
@ -1401,16 +1392,30 @@ private enum QueuedWakeup: Int32 {
case .camera:
context.openRootCamera()
case .savedMessages:
self.openChatWhenReady(peerId: context.context.account.peerId)
self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId)
}
}
}
})
}
private func openChatWhenReady(peerId: PeerId, messageId: MessageId? = nil) {
self.openChatWhenReadyDisposable.set((self.authorizedContext()
private func openChatWhenReady(accountId: AccountRecordId?, peerId: PeerId, messageId: MessageId? = nil) {
let signal = self.sharedContextPromise.get()
|> take(1)
|> mapToSignal { sharedContext -> Signal<AuthorizedApplicationContext, NoError> in
if let accountId = accountId {
sharedContext.switchToAccount(id: accountId)
return self.authorizedContext()
|> filter { context in
context.context.account.id == accountId
}
|> take(1)
} else {
return self.authorizedContext()
|> take(1)
}
}
self.openChatWhenReadyDisposable.set((signal
|> deliverOnMainQueue).start(next: { context in
context.openChatWithPeerId(peerId: peerId, messageId: messageId)
}))
@ -1434,7 +1439,7 @@ private enum QueuedWakeup: Int32 {
if response.notification.request.content.categoryIdentifier == "watch" {
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
}
self.openChatWhenReady(peerId: peerId, messageId: messageId)
self.openChatWhenReady(accountId: accountIdFromNotification(response.notification), peerId: peerId, messageId: messageId)
}
completionHandler()
} else if response.actionIdentifier == "reply", let peerId = peerIdFromNotification(response.notification) {
@ -1507,8 +1512,8 @@ private enum QueuedWakeup: Int32 {
private func registerForNotifications(context: AccountContext, authorize: Bool = true, completion: @escaping (Bool) -> Void = { _ in }) {
let presentationData = context.currentPresentationData.with { $0 }
let _ = (context.account.postbox.transaction { transaction -> Bool in
let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
let _ = (context.sharedContext.accountManager.transaction { transaction -> Bool in
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
return settings.displayNameOnLockscreen
}
|> deliverOnMainQueue).start(next: { displayNames in
@ -1594,7 +1599,7 @@ private enum QueuedWakeup: Int32 {
let queuedMutePolling = self.queuedMutePolling
self.queuedMutePolling = false
let _ = (context.context.account.postbox.transaction(ignoreDisabled: true, { transaction -> PostboxAccessChallengeData in
let _ = (context.context.sharedContext.accountManager.transaction(ignoreDisabled: true, { transaction -> PostboxAccessChallengeData in
return transaction.getAccessChallengeData()
})
|> deliverOnMainQueue).start(next: { accessChallengeData in
@ -1726,6 +1731,15 @@ private enum QueuedWakeup: Int32 {
}
}
@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 {
return nil
}
}
@available(iOS 10.0, *)
private func peerIdFromNotification(_ notification: UNNotification) -> PeerId? {
if let peerId = notification.request.content.userInfo["peerId"] as? Int64 {

View file

@ -7,34 +7,6 @@ import TelegramCore
import Display
import LegacyComponents
/*func applicationContext(networkArguments: NetworkInitializationArguments, applicationBindings: TelegramApplicationBindings, replyFromNotificationsActive: Signal<Bool, NoError>, backgroundAudioActive: Signal<Bool, NoError>, watchManagerArguments: Signal<WatchManagerArguments?, NoError>, sharedContext: SharedAccountContext, accountManager: AccountManager, rootPath: String, legacyBasePath: String, mainWindow: Window1, reinitializedNotificationSettings: @escaping () -> Void) -> Signal<ApplicationContext?, NoError> {
return currentAccount(allocateIfNotExists: true, networkArguments: networkArguments, supplementary: false, manager: accountManager, rootPath: rootPath, auxiliaryMethods: telegramAccountAuxiliaryMethods)
|> filter { $0 != nil }
|> deliverOnMainQueue
|> mapToSignal { account -> Signal<ApplicationContext?, NoError> in
if let account = account {
switch account {
case .upgrading:
preconditionFailure()
case let .unauthorized(account):
return currentPresentationDataAndSettings(postbox: account.postbox)
|> deliverOnMainQueue
|> map { dataAndSettings -> ApplicationContext? in
return .unauthorized(UnauthorizedApplicationContext(account: account, applicationBindings: applicationBindings))
}
case let .authorized(account):
return currentPresentationDataAndSettings(postbox: account.postbox)
|> deliverOnMainQueue
|> map { dataAndSettings -> ApplicationContext? in
return .authorized(AuthorizedApplicationContext(mainWindow: mainWindow, replyFromNotificationsActive: replyFromNotificationsActive, backgroundAudioActive: backgroundAudioActive, watchManagerArguments: watchManagerArguments, context: AccountContext(sharedContext: sharedContext, account: account, initialPresentationDataAndSettings: dataAndSettings), accountManager: accountManager, legacyBasePath: legacyBasePath, showCallsTab: dataAndSettings.callListSettings.showTab, reinitializedNotificationSettings: reinitializedNotificationSettings))
}
}
} else {
return .single(nil)
}
}
}*/
func isAccessLocked(data: PostboxAccessChallengeData, at timestamp: Int32) -> Bool {
if data.isLockable, let autolockDeadline = data.autolockDeadline, autolockDeadline <= timestamp {
return true
@ -183,7 +155,7 @@ final class AuthorizedApplicationContext {
}
var applicationBadge: Signal<Int32, NoError> {
return renderedTotalUnreadCount(postbox: self.context.account.postbox)
return renderedTotalUnreadCount(accountManager: self.context.sharedContext.accountManager, postbox: self.context.account.postbox)
|> map {
$0.0
}
@ -225,10 +197,9 @@ final class AuthorizedApplicationContext {
let runningWatchTasksPromise = Promise<WatchRunningTasks?>(nil)
let downloadPreferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings]))
let runningDownloadTasks = combineLatest(context.account.postbox.combinedView(keys: [downloadPreferencesKey]), context.account.shouldKeepBackgroundDownloadConnections.get())
|> map { views, shouldKeepBackgroundDownloadConnections -> Bool in
let settings: AutomaticMediaDownloadSettings = (views.views[downloadPreferencesKey] as? PreferencesView)?.values[ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings] as? AutomaticMediaDownloadSettings ?? AutomaticMediaDownloadSettings.defaultSettings
let runningDownloadTasks = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]), context.account.shouldKeepBackgroundDownloadConnections.get())
|> map { sharedData, shouldKeepBackgroundDownloadConnections -> Bool in
let settings: AutomaticMediaDownloadSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? AutomaticMediaDownloadSettings ?? AutomaticMediaDownloadSettings.defaultSettings
if !settings.downloadInBackground {
return false
}
@ -236,7 +207,7 @@ final class AuthorizedApplicationContext {
}
|> distinctUntilChanged
self.wakeupManager = WakeupManager(inForeground: context.sharedContext.applicationBindings.applicationInForeground, runningServiceTasks: context.account.importantTasksRunning, runningBackgroundLocationTasks: runningBackgroundLocationTasks, runningWatchTasks: runningWatchTasksPromise.get(), runningDownloadTasks: runningDownloadTasks)
self.wakeupManager = WakeupManager(accountManager: context.sharedContext.accountManager, inForeground: context.sharedContext.applicationBindings.applicationInForeground, runningServiceTasks: context.account.importantTasksRunning, runningBackgroundLocationTasks: runningBackgroundLocationTasks, runningWatchTasks: runningWatchTasksPromise.get(), runningDownloadTasks: runningDownloadTasks)
self.showCallsTab = showCallsTab
@ -248,7 +219,7 @@ final class AuthorizedApplicationContext {
context.attachOverlayMediaController(self.overlayMediaController)
var presentImpl: ((ViewController, Any?) -> Void)?
var openSettingsImpl: (() -> Void)?
let callManager = PresentationCallManager(account: context.account, getDeviceAccessData: {
let callManager = PresentationCallManager(accountManager: context.sharedContext.accountManager, account: context.account, getDeviceAccessData: {
return (context.currentPresentationData.with { $0 }, { c, a in
presentImpl?(c, a)
}, {
@ -377,12 +348,10 @@ final class AuthorizedApplicationContext {
let previousPasscodeState = Atomic<PasscodeState?>(value: nil)
let preferencesKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([ApplicationSpecificPreferencesKeys.presentationPasscodeSettings]))
self.passcodeStatusDisposable.set((combineLatest(queue: Queue.mainQueue(), context.account.postbox.combinedView(keys: [.accessChallengeData, preferencesKey]), context.sharedContext.applicationBindings.applicationIsActive)
|> map { view, isActive -> (PostboxAccessChallengeData, PresentationPasscodeSettings?, Bool) in
let accessChallengeData = (view.views[.accessChallengeData] as? AccessChallengeDataView)?.data ?? PostboxAccessChallengeData.none
let passcodeSettings = (view.views[preferencesKey] as! PreferencesView).values[ApplicationSpecificPreferencesKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings
self.passcodeStatusDisposable.set((combineLatest(queue: Queue.mainQueue(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), context.sharedContext.accountManager.accessChallengeData(), context.sharedContext.applicationBindings.applicationIsActive)
|> map { sharedData, accessChallengeDataView, isActive -> (PostboxAccessChallengeData, PresentationPasscodeSettings?, Bool) in
let accessChallengeData = accessChallengeDataView.data
let passcodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings
return (accessChallengeData, passcodeSettings, isActive)
}
|> map { accessChallengeData, passcodeSettings, isActive -> PasscodeState in
@ -424,7 +393,7 @@ final class AuthorizedApplicationContext {
if previousState?.isActive != updatedState.isActive || isLocked != strongSelf.isLocked {
if updatedAutolockDeadline != previousState?.challengeData.autolockDeadline {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(updatedAutolockDeadline)
transaction.setAccessChallengeData(data)
}).start()
@ -457,7 +426,7 @@ final class AuthorizedApplicationContext {
return
}
if value != nil {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(nil)
transaction.setAccessChallengeData(data)
}).start()
@ -481,19 +450,19 @@ final class AuthorizedApplicationContext {
guard let strongSelf = self else {
return
}
let _ = strongSelf.context.account.postbox.transaction({ transaction -> Void in
let _ = strongSelf.context.sharedContext.accountManager.transaction({ transaction -> Void in
var attempts: AccessChallengeAttempts?
if let attemptData = attemptData {
attempts = AccessChallengeAttempts(count: Int32(attemptData.numberOfInvalidAttempts), timestamp: Int32(attemptData.dateOfLastInvalidAttempt))
}
var data = transaction.getAccessChallengeData()
switch data {
case .none:
break
case let .numericalPassword(value, timeout, _):
data = .numericalPassword(value: value, timeout: timeout, attempts: attempts)
case let .plaintextPassword(value, timeout, _):
data = .plaintextPassword(value: value, timeout: timeout, attempts: attempts)
case .none:
break
case let .numericalPassword(value, timeout, _):
data = .numericalPassword(value: value, timeout: timeout, attempts: attempts)
case let .plaintextPassword(value, timeout, _):
data = .plaintextPassword(value: value, timeout: timeout, attempts: attempts)
}
transaction.setAccessChallengeData(data)
}).start()
@ -502,7 +471,7 @@ final class AuthorizedApplicationContext {
guard let strongSelf = self else {
return
}
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(nil)
transaction.setAccessChallengeData(data)
}).start()
@ -619,16 +588,13 @@ final class AuthorizedApplicationContext {
}
}))
let inAppPreferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.inAppNotificationSettings]))
self.inAppNotificationSettingsDisposable.set(((context.account.postbox.combinedView(keys: [inAppPreferencesKey])) |> deliverOnMainQueue).start(next: { [weak self] views in
self.inAppNotificationSettingsDisposable.set(((context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings])) |> deliverOnMainQueue).start(next: { [weak self] sharedData in
if let strongSelf = self {
if let view = views.views[inAppPreferencesKey] as? PreferencesView {
if let settings = view.values[ApplicationSpecificPreferencesKeys.inAppNotificationSettings] as? InAppNotificationSettings {
let previousSettings = strongSelf.inAppNotificationSettings
strongSelf.inAppNotificationSettings = settings
if let previousSettings = previousSettings, previousSettings.displayNameOnLockscreen != settings.displayNameOnLockscreen {
reinitializedNotificationSettings()
}
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings {
let previousSettings = strongSelf.inAppNotificationSettings
strongSelf.inAppNotificationSettings = settings
if let previousSettings = previousSettings, previousSettings.displayNameOnLockscreen != settings.displayNameOnLockscreen {
reinitializedNotificationSettings()
}
}
}
@ -1038,10 +1004,10 @@ final class AuthorizedApplicationContext {
}
})
let showCallsTabSignal = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.callListSettings])
|> map { view -> Bool in
let showCallsTabSignal = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings])
|> map { sharedData -> Bool in
var value = true
if let settings = view.values[ApplicationSpecificPreferencesKeys.callListSettings] as? CallListSettings {
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings] as? CallListSettings {
value = settings.showTab
}
return value

View file

@ -14,7 +14,7 @@ enum AccountImportProgressType {
case media
}
private func importedAccountData(basePath: String, documentsPath: String, account: TemporaryAccount, database: SqliteInterface) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
private func importedAccountData(basePath: String, documentsPath: String, accountManager: AccountManager, account: TemporaryAccount, database: SqliteInterface) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
let keychain = MTFileBasedKeychain(name: "Telegram", documentsPath: documentsPath)
guard let masterDatacenterId = keychain.object(forKey: "defaultDatacenterId", group: "persistent") as? Int else {
@ -33,7 +33,7 @@ private func importedAccountData(basePath: String, documentsPath: String, accoun
let importData = importPreferencesData(documentsPath: documentsPath, masterDatacenterId: Int32(masterDatacenterId), account: account, database: database)
|> mapToSignal { accountUserId -> Signal<(AccountImportProgressType, Float), AccountImportError> in
return importDatabaseData(account: account, basePath: basePath, database: database, accountUserId: accountUserId)
return importDatabaseData(accountManager: accountManager, account: account, basePath: basePath, database: database, accountUserId: accountUserId)
}
return importKeychain
@ -67,7 +67,7 @@ private func importPreferencesData(documentsPath: String, masterDatacenterId: In
}
}
private func importDatabaseData(account: TemporaryAccount, basePath: String, database: SqliteInterface, accountUserId: Int32) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
private func importDatabaseData(accountManager: AccountManager, account: TemporaryAccount, basePath: String, database: SqliteInterface, accountUserId: Int32) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
var importedAccountUser: Signal<Never, AccountImportError> = .complete()
if let (user, presence) = loadLegacyUser(database: database, id: accountUserId) {
@ -85,7 +85,7 @@ private func importDatabaseData(account: TemporaryAccount, basePath: String, dat
/*let importedFiles = loadLegacyFiles(account: account, basePath: basePath, accountPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: accountUserId), database: database)
|> introduceError(AccountImportError.self)*/
let importedLegacyPreferences = importLegacyPreferences(account: account, documentsPath: basePath + "/Documents", database: database)
let importedLegacyPreferences = importLegacyPreferences(accountManager: accountManager, account: account, documentsPath: basePath + "/Documents", database: database)
|> introduceError(AccountImportError.self)
return importedAccountUser
@ -221,7 +221,7 @@ func importedLegacyAccount(basePath: String, accountManager: AccountManager, pre
return temporaryAccount(manager: accountManager, rootPath: rootPathForBasePath(basePath))
|> introduceError(AccountImportError.self)
|> mapToSignal { account -> Signal<ImportedLegacyAccountEvent, AccountImportError> in
let actions = importedAccountData(basePath: basePath, documentsPath: documentsPath, account: account, database: database)
let actions = importedAccountData(basePath: basePath, documentsPath: documentsPath, accountManager: accountManager, account: account, database: database)
var result = actions
|> map { typeAndProgress -> ImportedLegacyAccountEvent in
return .progress(typeAndProgress.0, typeAndProgress.1)

View file

@ -56,7 +56,7 @@ private func convertLegacyProxyPort(_ value: Int) -> Int32 {
}
}
func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, database: SqliteInterface) -> Signal<Never, NoError> {
func importLegacyPreferences(accountManager: AccountManager, account: TemporaryAccount, documentsPath: String, database: SqliteInterface) -> Signal<Never, NoError> {
return deferred { () -> Signal<Never, NoError> in
var presentationState: TGPresentationState?
if let value = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/presentation.dat") as? TGPresentationState {
@ -172,8 +172,8 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
localization = NSKeyedUnarchiver.unarchiveObject(withFile: nativeDocumentsPath + "/localization") as? TGLocalization
}
return account.postbox.transaction { transaction -> Void in
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.presentationThemeSettings, { current in
return accountManager.transaction { transaction -> Signal<Void, NoError> in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { current in
var settings = (current as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
if let presentationState = presentationState {
switch presentationState.pallete {
@ -249,7 +249,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings, { current in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, { current in
var settings: AutomaticMediaDownloadSettings = current as? AutomaticMediaDownloadSettings ?? .defaultSettings
if let preferences = autoDownloadPreferences, !preferences.isDefaultPreferences() {
@ -285,7 +285,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.inAppNotificationSettings, { current in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings, { current in
var settings: InAppNotificationSettings = current as? InAppNotificationSettings ?? .defaultSettings
if let soundEnabled = soundEnabled {
settings.playSounds = soundEnabled
@ -299,7 +299,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.voiceCallSettings, { current in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.voiceCallSettings, { current in
var settings: VoiceCallSettings = current as? VoiceCallSettings ?? .defaultSettings
if let callsDataUsageMode = callsDataUsageMode {
switch callsDataUsageMode {
@ -320,7 +320,119 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
return settings
})
transaction.updatePreferencesEntry(key: PreferencesKeys.proxySettings, { current in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.callListSettings, { current in
var settings: CallListSettings = current as? CallListSettings ?? .defaultSettings
if let showCallsTab = showCallsTab {
settings.showTab = showCallsTab
}
return settings
})
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings, { current in
var settings: PresentationPasscodeSettings = current as? PresentationPasscodeSettings ?? .defaultSettings
if let passcodeChallenge = passcodeChallenge {
transaction.setAccessChallengeData(passcodeChallenge)
switch passcodeChallenge {
case .none:
break
case let .numericalPassword(_, timeout, _):
settings.autolockTimeout = timeout
case let .plaintextPassword(_, timeout, _):
settings.autolockTimeout = timeout
}
settings.enableBiometrics = passcodeEnableBiometrics
}
return settings
})
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.stickerSettings, { current in
var settings: StickerSettings = current as? StickerSettings ?? .defaultSettings
if let stickersSuggestMode = stickersSuggestMode {
switch stickersSuggestMode {
case 1:
settings.emojiStickerSuggestionMode = .installed
case 2:
settings.emojiStickerSuggestionMode = .none
default:
settings.emojiStickerSuggestionMode = .all
}
}
return settings
})
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { current in
var settings: MusicPlaybackSettings = current as? MusicPlaybackSettings ?? .defaultSettings
if let musicPlayerOrderType = musicPlayerOrderType {
switch musicPlayerOrderType {
case 1:
settings.order = .reversed
case 2:
settings.order = .random
default:
settings.order = .regular
}
}
if let musicPlayerRepeatType = musicPlayerRepeatType {
switch musicPlayerRepeatType {
case 1:
settings.looping = .all
case 2:
settings.looping = .item
default:
settings.looping = .none
}
}
return settings
})
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.instantPagePresentationSettings, { current in
var settings: InstantPagePresentationSettings = current as? InstantPagePresentationSettings ?? .defaultSettings
if let instantPageFontSize = instantPageFontSize {
switch instantPageFontSize {
case 0.85:
settings.fontSize = .small
case 1.15:
settings.fontSize = .large
case 1.30:
settings.fontSize = .xlarge
case 1.50:
settings.fontSize = .xxlarge
default:
settings.fontSize = .standard
}
}
if let instantPageFontSerif = instantPageFontSerif {
settings.forceSerif = instantPageFontSerif == 1
}
if let instantPageTheme = instantPageTheme {
switch instantPageTheme {
case 1:
settings.themeType = .sepia
case 2:
settings.themeType = .gray
case 3:
settings.themeType = .dark
default:
settings.themeType = .light
}
}
if let instantPageAutoNightMode = instantPageAutoNightMode {
settings.autoNightMode = instantPageAutoNightMode == 1
}
return settings
})
if let localization = localization {
transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in
var entries: [LocalizationEntry] = []
for (key, value) in localization.dict() {
entries.append(LocalizationEntry.string(key: key, value: value))
}
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: localization.code, localizedName: "", localization: Localization(version: 0, entries: entries), customPluralizationCode: nil), secondaryComponent: nil)
})
}
transaction.updateSharedData(SharedDataKeys.proxySettings, { current in
var settings: ProxySettings = current as? ProxySettings ?? .defaultSettings
if let callsUseProxy = callsUseProxy {
settings.useForCalls = callsUseProxy
@ -364,134 +476,25 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.stickerSettings, { current in
var settings: StickerSettings = current as? StickerSettings ?? .defaultSettings
if let stickersSuggestMode = stickersSuggestMode {
switch stickersSuggestMode {
case 1:
settings.emojiStickerSuggestionMode = .installed
case 2:
settings.emojiStickerSuggestionMode = .none
default:
settings.emojiStickerSuggestionMode = .all
return account.postbox.transaction { transaction -> Void in
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.contactSynchronizationSettings, { current in
var settings: ContactSynchronizationSettings = current as? ContactSynchronizationSettings ?? .defaultSettings
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
settings.synchronizeDeviceContacts = false
}
}
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.contactSynchronizationSettings, { current in
var settings: ContactSynchronizationSettings = current as? ContactSynchronizationSettings ?? .defaultSettings
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
settings.synchronizeDeviceContacts = false
}
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.callListSettings, { current in
var settings: CallListSettings = current as? CallListSettings ?? .defaultSettings
if let showCallsTab = showCallsTab {
settings.showTab = showCallsTab
}
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.presentationPasscodeSettings, { current in
var settings: PresentationPasscodeSettings = current as? PresentationPasscodeSettings ?? .defaultSettings
if let passcodeChallenge = passcodeChallenge {
transaction.setAccessChallengeData(passcodeChallenge)
switch passcodeChallenge {
case .none:
break
case let .numericalPassword(_, timeout, _):
settings.autolockTimeout = timeout
case let .plaintextPassword(_, timeout, _):
settings.autolockTimeout = timeout
}
settings.enableBiometrics = passcodeEnableBiometrics
}
return settings
})
if let localization = localization {
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
var entries: [LocalizationEntry] = []
for (key, value) in localization.dict() {
entries.append(LocalizationEntry.string(key: key, value: value))
}
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: localization.code, localizedName: "", localization: Localization(version: 0, entries: entries), customPluralizationCode: nil), secondaryComponent: nil)
return settings
})
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
}
if let allowSecretWebpagesInitialized = allowSecretWebpagesInitialized, allowSecretWebpagesInitialized, let allowSecretWebpages = allowSecretWebpages {
ApplicationSpecificNotice.setSecretChatLinkPreviews(transaction: transaction, value: allowSecretWebpages)
}
}
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
}
if let allowSecretWebpagesInitialized = allowSecretWebpagesInitialized, allowSecretWebpagesInitialized, let allowSecretWebpages = allowSecretWebpages {
ApplicationSpecificNotice.setSecretChatLinkPreviews(transaction: transaction, value: allowSecretWebpages)
}
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.musicPlaybackSettings, { current in
var settings: MusicPlaybackSettings = current as? MusicPlaybackSettings ?? .defaultSettings
if let musicPlayerOrderType = musicPlayerOrderType {
switch musicPlayerOrderType {
case 1:
settings.order = .reversed
case 2:
settings.order = .random
default:
settings.order = .regular
}
}
if let musicPlayerRepeatType = musicPlayerRepeatType {
switch musicPlayerRepeatType {
case 1:
settings.looping = .all
case 2:
settings.looping = .item
default:
settings.looping = .none
}
}
return settings
})
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.instantPagePresentationSettings, { current in
var settings: InstantPagePresentationSettings = current as? InstantPagePresentationSettings ?? .defaultSettings
if let instantPageFontSize = instantPageFontSize {
switch instantPageFontSize {
case 0.85:
settings.fontSize = .small
case 1.15:
settings.fontSize = .large
case 1.30:
settings.fontSize = .xlarge
case 1.50:
settings.fontSize = .xxlarge
default:
settings.fontSize = .standard
}
}
if let instantPageFontSerif = instantPageFontSerif {
settings.forceSerif = instantPageFontSerif == 1
}
if let instantPageTheme = instantPageTheme {
switch instantPageTheme {
case 1:
settings.themeType = .sepia
case 2:
settings.themeType = .gray
case 3:
settings.themeType = .dark
default:
settings.themeType = .light
}
}
if let instantPageAutoNightMode = instantPageAutoNightMode {
settings.autoNightMode = instantPageAutoNightMode == 1
}
return settings
})
}
|> switchToLatest
|> ignoreValues
}
}

View file

@ -242,9 +242,9 @@ final class NotificationManager {
func commitRemoteNotification(context: AccountContext, originalRequestId: NotificationManagedNotificationRequestId?, messageIds: [MessageId]) -> Signal<Void, NoError> {
return context.account.postbox.transaction { transaction -> ([(MessageId, [Message], Bool, PeerMessageSound, Bool)], Bool) in
var isLocked = false
if isAccessLocked(data: transaction.getAccessChallengeData(), at: Int32(CFAbsoluteTimeGetCurrent())) {
/*if isAccessLocked(data: transaction.getAccessChallengeData(), at: Int32(CFAbsoluteTimeGetCurrent())) {
isLocked = true
}
}*/
var results: [(MessageId, [Message], Bool, PeerMessageSound, Bool)] = []
var updatedMessageIds = messageIds

View file

@ -45,6 +45,7 @@ private struct CombinedRunningImportantTasks: Equatable {
}
final class WakeupManager {
private let accountManager: AccountManager
private var state = WakeupManagerState()
private let isProcessingNotificationsValue = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -68,7 +69,9 @@ final class WakeupManager {
private var wakeupResultSubscribers: [(Int32, ([MessageId]) -> Signal<Void, NoError>)] = []
init(inForeground: Signal<Bool, NoError>, runningServiceTasks: Signal<AccountRunningImportantTasks, NoError>, runningBackgroundLocationTasks: Signal<Bool, NoError>, runningWatchTasks: Signal<WatchRunningTasks?, NoError>, runningDownloadTasks: Signal<Bool, NoError>) {
init(accountManager: AccountManager, inForeground: Signal<Bool, NoError>, runningServiceTasks: Signal<AccountRunningImportantTasks, NoError>, runningBackgroundLocationTasks: Signal<Bool, NoError>, runningWatchTasks: Signal<WatchRunningTasks?, NoError>, runningDownloadTasks: Signal<Bool, NoError>) {
self.accountManager = accountManager
self.inForegroundDisposable = (inForeground |> distinctUntilChanged |> deliverOnMainQueue).start(next: { [weak self] value in
if let strongSelf = self {
if value {
@ -133,14 +136,20 @@ final class WakeupManager {
collectedSignals.append(first.1(messageIds))
}
}
let accountManager = self.accountManager
return combineLatest(collectedSignals)
|> map { _ -> Void in
return Void()
} |> mapToSignal { _ -> Signal<Int32?, NoError> in
if !messageIds.isEmpty {
return account.postbox.transaction { transaction -> Int32? in
let (unreadCount, _) = renderedTotalUnreadCount(transaction: transaction)
return unreadCount
return accountManager.transaction { transaction -> InAppNotificationSettings in
return transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
}
|> mapToSignal { inAppSettings -> Signal<Int32?, NoError> in
return account.postbox.transaction { transaction -> Int32? in
let (unreadCount, _) = renderedTotalUnreadCount(inAppNotificationSettings: inAppSettings, transaction: transaction)
return unreadCount
}
}
} else {
return .single(nil)

View file

@ -65,10 +65,9 @@ final class WatchCommunicationManager {
strongSelf.server.setMicAccessAllowed(true)
strongSelf.server.pushContext()
let watchPresetSettingsKey = ApplicationSpecificPreferencesKeys.watchPresetSettings
strongSelf.presets.set(context.context.account.postbox.preferencesView(keys: [watchPresetSettingsKey])
|> map({ preferences -> WatchPresetSettings in
return (preferences.values[watchPresetSettingsKey] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings
strongSelf.presets.set(context.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.watchPresetSettings])
|> map({ sharedData -> WatchPresetSettings in
return (sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings
}))
} else {
strongSelf.accountContext.set(.single(nil))

View file

@ -82,13 +82,11 @@ class TodayViewController: UIViewController, NCWidgetProviding {
} else {
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement()
account = accountManager(basePath: rootPath + "/accounts-metadata")
|> take(1)
|> mapToSignal { accountManager -> Signal<Account, NoError> in
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Account, NoError> in
if let account = account {
switch account {
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Account, NoError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
@ -96,13 +94,11 @@ class TodayViewController: UIViewController, NCWidgetProviding {
return .single(account)
case .unauthorized:
return .complete()
}
} else {
return .complete()
}
} else {
return .complete()
}
}
|> take(1)
}
let applicationInterface = account |> afterNext { account in

@ -1 +1 @@
Subproject commit d444a36f9875c56902bef4d776098215cb3aa4db
Subproject commit 709df1faeffdd6fefc72bb8a1853b65a5e803bdc

@ -1 +1 @@
Subproject commit 89531617a0b77014aa69dd8043b67858218e6a1c
Subproject commit 67e60e8e8b4ab11daa5b52e732d1a62232b2d31a

@ -1 +1 @@
Subproject commit f811d2a6475398acafae51f8b562b65d486b8bfd
Subproject commit 494ba4dc7b8ed5962c64ac1bf3b1efd8b4ec77d7

@ -1 +1 @@
Subproject commit 668207ab55d2e58843b0614260f7738c3d6116c4
Subproject commit 84231fb6fcbb39f72b50b2812c728cab8c659b52

@ -1 +1 @@
Subproject commit 9cd176142e2b34e0062e13f09101ac6364f83b52
Subproject commit 3540d5ea002762f50d38ad9cd01ada7f8af2f023