Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-02-17 17:50:39 +04:00
commit 8fe68fd1ed
13 changed files with 110 additions and 78 deletions

View File

@ -55,7 +55,25 @@ enum IntentHandlingError {
@available(iOSApplicationExtension 10.0, iOS 10.0, *) @available(iOSApplicationExtension 10.0, iOS 10.0, *)
@objc(IntentHandler) @objc(IntentHandler)
class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling { class IntentHandler: INExtension {
override public func handler(for intent: INIntent) -> Any {
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
if intent is SelectAvatarFriendsIntent {
return AvatarsIntentHandler()
} else if intent is SelectFriendsIntent {
return FriendsIntentHandler()
} else {
return DefaultIntentHandler()
}
} else {
return DefaultIntentHandler()
}
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
@objc(IntentHandler)
class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling {
private let accountPromise = Promise<Account?>() private let accountPromise = Promise<Account?>()
private let allAccounts = Promise<[(AccountRecordId, PeerId, Bool)]>() private let allAccounts = Promise<[(AccountRecordId, PeerId, Bool)]>()
@ -106,7 +124,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement() initializeAccountManagement()
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true) let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
self.accountManager = accountManager self.accountManager = accountManager
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId) let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
@ -195,20 +213,6 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
self.searchDisposable.dispose() self.searchDisposable.dispose()
} }
override public func handler(for intent: INIntent) -> Any {
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
if intent is SelectAvatarFriendsIntent {
return AvatarsIntentHandler()
} else if intent is SelectFriendsIntent {
return FriendsIntentHandler()
} else {
return self
}
} else {
return self
}
}
enum ResolveResult { enum ResolveResult {
case success(INPerson) case success(INPerson)
case disambiguation([INPerson]) case disambiguation([INPerson])
@ -789,7 +793,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
var accountResults: [Signal<INObjectSection<Friend>, Error>] = [] var accountResults: [Signal<INObjectSection<Friend>, Error>] = []
for (accountId, accountPeerId, _) in accounts { for (accountId, accountPeerId, _) in accounts {
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> INObjectSection<Friend> in accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, transaction: { postbox, transaction -> INObjectSection<Friend> in
var accountTitle: String = "" var accountTitle: String = ""
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser { if let peer = transaction.getPeer(accountPeerId) as? TelegramUser {
if let username = peer.username, !username.isEmpty { if let username = peer.username, !username.isEmpty {
@ -958,7 +962,7 @@ private final class WidgetIntentHandler {
var accountResults: [Signal<INObjectSection<Friend>, Error>] = [] var accountResults: [Signal<INObjectSection<Friend>, Error>] = []
for (accountId, accountPeerId, _) in accounts { for (accountId, accountPeerId, _) in accounts {
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> INObjectSection<Friend> in accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, transaction: { postbox, transaction -> INObjectSection<Friend> in
var accountTitle: String = "" var accountTitle: String = ""
if let peer = transaction.getPeer(accountPeerId) as? TelegramUser { if let peer = transaction.getPeer(accountPeerId) as? TelegramUser {
if let username = peer.username, !username.isEmpty { if let username = peer.username, !username.isEmpty {
@ -1041,7 +1045,7 @@ private final class WidgetIntentHandler {
if !isActive { if !isActive {
continue continue
} }
accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> [Friend] in accountResults.append(accountTransaction(rootPath: rootPath, id: accountId, encryptionParameters: encryptionParameters, isReadOnly: true, transaction: { postbox, transaction -> [Friend] in
var peers: [Peer] = [] var peers: [Peer] = []
for id in getRecentPeers(transaction: transaction) { for id in getRecentPeers(transaction: transaction) {

View File

@ -59,22 +59,6 @@ private let accountAuxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInpu
return nil return nil
}) })
private struct ApplicationSettings {
let logging: LoggingSettings
}
private func applicationSettings(accountManager: AccountManager) -> Signal<ApplicationSettings, NoError> {
return accountManager.transaction { transaction -> ApplicationSettings in
let loggingSettings: LoggingSettings
if let value = transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings {
loggingSettings = value
} else {
loggingSettings = LoggingSettings.defaultSettings
}
return ApplicationSettings(logging: loggingSettings)
}
}
private func rootPathForBasePath(_ appGroupPath: String) -> String { private func rootPathForBasePath(_ appGroupPath: String) -> String {
return appGroupPath + "/telegram-data" return appGroupPath + "/telegram-data"
} }
@ -155,7 +139,7 @@ struct Provider: IntentTimelineProvider {
var friendsByAccount: [Signal<[ParsedPeer], NoError>] = [] var friendsByAccount: [Signal<[ParsedPeer], NoError>] = []
for (accountId, items) in itemsByAccount { for (accountId, items) in itemsByAccount {
friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> [ParsedPeer] in friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, isReadOnly: true, transaction: { postbox, transaction -> [ParsedPeer] in
guard let state = transaction.getState() as? AuthorizedAccountState else { guard let state = transaction.getState() as? AuthorizedAccountState else {
return [] return []
} }
@ -313,7 +297,7 @@ struct AvatarsProvider: IntentTimelineProvider {
var friendsByAccount: [Signal<[ParsedPeer], NoError>] = [] var friendsByAccount: [Signal<[ParsedPeer], NoError>] = []
for (accountId, items) in itemsByAccount { for (accountId, items) in itemsByAccount {
friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, transaction: { postbox, transaction -> [ParsedPeer] in friendsByAccount.append(accountTransaction(rootPath: rootPath, id: AccountRecordId(rawValue: accountId), encryptionParameters: encryptionParameters, isReadOnly: true, transaction: { postbox, transaction -> [ParsedPeer] in
guard let state = transaction.getState() as? AuthorizedAccountState else { guard let state = transaction.getState() as? AuthorizedAccountState else {
return [] return []
} }

View File

@ -65,7 +65,7 @@ final class AccountManagerImpl {
} }
} }
fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, temporarySessionId: Int64) { fileprivate init?(queue: Queue, basePath: String, isTemporary: Bool, isReadOnly: Bool, temporarySessionId: Int64) {
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
self.queue = queue self.queue = queue
@ -73,11 +73,11 @@ final class AccountManagerImpl {
self.atomicStatePath = "\(basePath)/atomic-state" self.atomicStatePath = "\(basePath)/atomic-state"
self.temporarySessionId = temporarySessionId self.temporarySessionId = temporarySessionId
let _ = try? FileManager.default.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil) let _ = try? FileManager.default.createDirectory(atPath: basePath, withIntermediateDirectories: true, attributes: nil)
guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, encryptionParameters: nil, upgradeProgress: { _ in }) else { guard let guardValueBox = SqliteValueBox(basePath: basePath + "/guard_db", queue: queue, isTemporary: isTemporary, isReadOnly: false, encryptionParameters: nil, upgradeProgress: { _ in }) else {
return nil return nil
} }
self.guardValueBox = guardValueBox self.guardValueBox = guardValueBox
guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, encryptionParameters: nil, upgradeProgress: { _ in }) else { guard let valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: nil, upgradeProgress: { _ in }) else {
return nil return nil
} }
self.valueBox = valueBox self.valueBox = valueBox
@ -468,7 +468,7 @@ public final class AccountManager {
return AccountManagerImpl.getCurrentRecords(basePath: basePath) return AccountManagerImpl.getCurrentRecords(basePath: basePath)
} }
public init(basePath: String, isTemporary: Bool) { public init(basePath: String, isTemporary: Bool, isReadOnly: Bool) {
self.queue = sharedQueue self.queue = sharedQueue
self.basePath = basePath self.basePath = basePath
var temporarySessionId: Int64 = 0 var temporarySessionId: Int64 = 0
@ -476,7 +476,7 @@ public final class AccountManager {
self.temporarySessionId = temporarySessionId self.temporarySessionId = temporarySessionId
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
if let value = AccountManagerImpl(queue: queue, basePath: basePath, isTemporary: isTemporary, temporarySessionId: temporarySessionId) { if let value = AccountManagerImpl(queue: queue, basePath: basePath, isTemporary: isTemporary, isReadOnly: isReadOnly, temporarySessionId: temporarySessionId) {
return value return value
} else { } else {
preconditionFailure() preconditionFailure()

View File

@ -28,11 +28,16 @@ import sqlcipher
public final class Database { public final class Database {
internal var handle: OpaquePointer? = nil internal var handle: OpaquePointer? = nil
public init?(_ location: String) { public init?(_ location: String, readOnly: Bool) {
if location != ":memory:" { if location != ":memory:" {
let _ = open(location + "-guard", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR) let _ = open(location + "-guard", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)
} }
let flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX let flags: Int32
if readOnly {
flags = SQLITE_OPEN_READONLY
} else {
flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX
}
let res = sqlite3_open_v2(location, &self.handle, flags, nil) let res = sqlite3_open_v2(location, &self.handle, flags, nil)
if res != SQLITE_OK { if res != SQLITE_OK {
postboxLog("sqlite3_open_v2: \(res)") postboxLog("sqlite3_open_v2: \(res)")

View File

@ -1125,7 +1125,7 @@ func debugRestoreState(basePath:String, name: String) {
private let sharedQueue = Queue(name: "org.telegram.postbox.Postbox") private let sharedQueue = Queue(name: "org.telegram.postbox.Postbox")
public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool) -> Signal<PostboxResult, NoError> { public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration, encryptionParameters: ValueBoxEncryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32, isTemporary: Bool, isReadOnly: Bool) -> Signal<PostboxResult, NoError> {
let queue = sharedQueue let queue = sharedQueue
return Signal { subscriber in return Signal { subscriber in
queue.async { queue.async {
@ -1138,7 +1138,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
guard var valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, encryptionParameters: encryptionParameters, upgradeProgress: { progress in guard var valueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress)) subscriber.putNext(.upgrading(progress))
}) else { }) else {
subscriber.putNext(.error) subscriber.putNext(.error)
@ -1161,7 +1161,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
postboxLog("Version \(userVersion) is newer than supported") postboxLog("Version \(userVersion) is newer than supported")
assertionFailure("Version \(userVersion) is newer than supported") assertionFailure("Version \(userVersion) is newer than supported")
valueBox.drop() valueBox.drop()
guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, encryptionParameters: encryptionParameters, upgradeProgress: { progress in guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress)) subscriber.putNext(.upgrading(progress))
}) else { }) else {
subscriber.putNext(.error) subscriber.putNext(.error)
@ -1185,7 +1185,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
valueBox.internalClose() valueBox.internalClose()
let _ = try? FileManager.default.removeItem(atPath: basePath + "/db") let _ = try? FileManager.default.removeItem(atPath: basePath + "/db")
let _ = try? FileManager.default.moveItem(atPath: updatedPath, toPath: basePath + "/db") let _ = try? FileManager.default.moveItem(atPath: updatedPath, toPath: basePath + "/db")
guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, encryptionParameters: encryptionParameters, upgradeProgress: { progress in guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress)) subscriber.putNext(.upgrading(progress))
}) else { }) else {
subscriber.putNext(.error) subscriber.putNext(.error)
@ -1199,7 +1199,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
assertionFailure("Couldn't find any upgrade for \(userVersion)") assertionFailure("Couldn't find any upgrade for \(userVersion)")
postboxLog("Couldn't find any upgrade for \(userVersion)") postboxLog("Couldn't find any upgrade for \(userVersion)")
valueBox.drop() valueBox.drop()
guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, encryptionParameters: encryptionParameters, upgradeProgress: { progress in guard let updatedValueBox = SqliteValueBox(basePath: basePath + "/db", queue: queue, isTemporary: isTemporary, isReadOnly: isReadOnly, encryptionParameters: encryptionParameters, upgradeProgress: { progress in
subscriber.putNext(.upgrading(progress)) subscriber.putNext(.upgrading(progress))
}) else { }) else {
subscriber.putNext(.error) subscriber.putNext(.error)
@ -1538,10 +1538,12 @@ public final class Postbox {
self.messageHistoryMetadataTable.setShouldReindexUnreadCountsState(value: reindexUnreadVersion) self.messageHistoryMetadataTable.setShouldReindexUnreadCountsState(value: reindexUnreadVersion)
} }
//#if DEBUG //#if DEBUG
if !isTemporary {
self.messageHistoryMetadataTable.setShouldReindexUnreadCounts(value: true) self.messageHistoryMetadataTable.setShouldReindexUnreadCounts(value: true)
}
//#endif //#endif
if self.messageHistoryMetadataTable.shouldReindexUnreadCounts() { if !isTemporary && self.messageHistoryMetadataTable.shouldReindexUnreadCounts() {
self.groupMessageStatsTable.removeAll() self.groupMessageStatsTable.removeAll()
let startTime = CFAbsoluteTimeGetCurrent() let startTime = CFAbsoluteTimeGetCurrent()
let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self) let (totalStates, summaries) = self.chatListIndexTable.debugReindexUnreadCounts(postbox: self)

View File

@ -162,6 +162,7 @@ public final class SqliteValueBox: ValueBox {
fileprivate let basePath: String fileprivate let basePath: String
private let isTemporary: Bool private let isTemporary: Bool
private let isReadOnly: Bool
private let inMemory: Bool private let inMemory: Bool
private let encryptionParameters: ValueBoxEncryptionParameters? private let encryptionParameters: ValueBoxEncryptionParameters?
private let databasePath: String private let databasePath: String
@ -200,14 +201,15 @@ public final class SqliteValueBox: ValueBox {
private let queue: Queue private let queue: Queue
public init?(basePath: String, queue: Queue, isTemporary: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) { public init?(basePath: String, queue: Queue, isTemporary: Bool, isReadOnly: Bool, encryptionParameters: ValueBoxEncryptionParameters?, upgradeProgress: (Float) -> Void, inMemory: Bool = false) {
self.basePath = basePath self.basePath = basePath
self.isTemporary = isTemporary self.isTemporary = isTemporary
self.isReadOnly = isReadOnly
self.inMemory = inMemory self.inMemory = inMemory
self.encryptionParameters = encryptionParameters self.encryptionParameters = encryptionParameters
self.databasePath = basePath + "/db_sqlite" self.databasePath = basePath + "/db_sqlite"
self.queue = queue self.queue = queue
if let database = self.openDatabase(encryptionParameters: encryptionParameters, isTemporary: isTemporary, upgradeProgress: upgradeProgress) { if let database = self.openDatabase(encryptionParameters: encryptionParameters, isTemporary: isTemporary, isReadOnly: isReadOnly, upgradeProgress: upgradeProgress) {
self.database = database self.database = database
} else { } else {
return nil return nil
@ -224,7 +226,7 @@ public final class SqliteValueBox: ValueBox {
self.database = nil self.database = nil
} }
private func openDatabase(encryptionParameters: ValueBoxEncryptionParameters?, isTemporary: Bool, upgradeProgress: (Float) -> Void) -> Database? { private func openDatabase(encryptionParameters: ValueBoxEncryptionParameters?, isTemporary: Bool, isReadOnly: Bool, upgradeProgress: (Float) -> Void) -> Database? {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
checkpoints.set(nil) checkpoints.set(nil)
@ -261,18 +263,23 @@ public final class SqliteValueBox: ValueBox {
#endif #endif
var database: Database var database: Database
if let result = Database(self.inMemory ? ":memory:" : path) { if let result = Database(self.inMemory ? ":memory:" : path, readOnly: isReadOnly) {
database = result database = result
} else { } else {
postboxLog("Couldn't open DB") postboxLog("Couldn't open DB")
if isReadOnly {
postboxLog("Readonly, exiting")
return nil
}
let tempPath = basePath + "_test\(arc4random())" let tempPath = basePath + "_test\(arc4random())"
enum TempError: Error { enum TempError: Error {
case generic case generic
} }
do { do {
try FileManager.default.createDirectory(atPath: tempPath, withIntermediateDirectories: true, attributes: nil) try FileManager.default.createDirectory(atPath: tempPath, withIntermediateDirectories: true, attributes: nil)
let testDatabase = Database(tempPath + "/test_db")! let testDatabase = Database(tempPath + "/test_db", readOnly: false)!
var resultCode = testDatabase.execute("PRAGMA journal_mode=WAL") var resultCode = testDatabase.execute("PRAGMA journal_mode=WAL")
if !resultCode { if !resultCode {
throw TempError.generic throw TempError.generic
@ -309,7 +316,7 @@ public final class SqliteValueBox: ValueBox {
assert(resultCode) assert(resultCode)
if self.isEncrypted(database) { if self.isEncrypted(database) {
if isTemporary { if isTemporary || isReadOnly {
return nil return nil
} }
postboxLog("Encryption key is invalid") postboxLog("Encryption key is invalid")
@ -317,7 +324,7 @@ public final class SqliteValueBox: ValueBox {
for fileName in dabaseFileNames { for fileName in dabaseFileNames {
let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)") let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)")
} }
database = Database(path)! database = Database(path, readOnly: false)!
resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32") resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32")
assert(resultCode) assert(resultCode)
@ -329,11 +336,15 @@ public final class SqliteValueBox: ValueBox {
} }
} else { } else {
postboxLog("Encryption key is required") postboxLog("Encryption key is required")
if isReadOnly {
return nil
}
assert(false) assert(false)
for fileName in dabaseFileNames { for fileName in dabaseFileNames {
let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)") let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)")
} }
database = Database(path)! database = Database(path, readOnly: false)!
resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32") resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32")
assert(resultCode) assert(resultCode)
@ -344,6 +355,10 @@ public final class SqliteValueBox: ValueBox {
let hexKey = hexString(encryptionParameters.key.data + encryptionParameters.salt.data) let hexKey = hexString(encryptionParameters.key.data + encryptionParameters.salt.data)
if FileManager.default.fileExists(atPath: path) { if FileManager.default.fileExists(atPath: path) {
if isReadOnly {
return nil
}
postboxLog("Reencrypting database") postboxLog("Reencrypting database")
database = self.reencryptInPlace(database: database, encryptionParameters: encryptionParameters) database = self.reencryptInPlace(database: database, encryptionParameters: encryptionParameters)
@ -353,7 +368,7 @@ public final class SqliteValueBox: ValueBox {
for fileName in dabaseFileNames { for fileName in dabaseFileNames {
let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)") let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)")
} }
database = Database(path)! database = Database(path, readOnly: false)!
resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32") resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32")
assert(resultCode) assert(resultCode)
@ -373,10 +388,14 @@ public final class SqliteValueBox: ValueBox {
postboxLog("Encryption setup failed") postboxLog("Encryption setup failed")
//assert(false) //assert(false)
if isReadOnly {
return nil
}
for fileName in dabaseFileNames { for fileName in dabaseFileNames {
let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)") let _ = try? FileManager.default.removeItem(atPath: basePath + "/\(fileName)")
} }
database = Database(path)! database = Database(path, readOnly: false)!
resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32") resultCode = database.execute("PRAGMA cipher_plaintext_header_size=32")
assert(resultCode) assert(resultCode)
@ -459,9 +478,14 @@ public final class SqliteValueBox: ValueBox {
public func begin() { public func begin() {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
if self.isReadOnly {
let resultCode = self.database.execute("BEGIN DEFERRED")
assert(resultCode)
} else {
let resultCode = self.database.execute("BEGIN IMMEDIATE") let resultCode = self.database.execute("BEGIN IMMEDIATE")
assert(resultCode) assert(resultCode)
} }
}
public func commit() { public func commit() {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
@ -477,9 +501,14 @@ public final class SqliteValueBox: ValueBox {
private func beginInternal(database: Database) { private func beginInternal(database: Database) {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
if self.isReadOnly {
let resultCode = database.execute("BEGIN DEFERRED")
assert(resultCode)
} else {
let resultCode = database.execute("BEGIN IMMEDIATE") let resultCode = database.execute("BEGIN IMMEDIATE")
assert(resultCode) assert(resultCode)
} }
}
private func commitInternal(database: Database) { private func commitInternal(database: Database) {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
@ -2074,6 +2103,10 @@ public final class SqliteValueBox: ValueBox {
precondition(self.queue.isCurrent()) precondition(self.queue.isCurrent())
self.clearStatements() self.clearStatements()
if self.isReadOnly {
preconditionFailure()
}
self.lock.lock() self.lock.lock()
self.database = nil self.database = nil
self.lock.unlock() self.lock.unlock()
@ -2084,7 +2117,7 @@ public final class SqliteValueBox: ValueBox {
let _ = try? FileManager.default.removeItem(atPath: self.basePath + "/\(fileName)") let _ = try? FileManager.default.removeItem(atPath: self.basePath + "/\(fileName)")
} }
self.database = self.openDatabase(encryptionParameters: self.encryptionParameters, isTemporary: self.isTemporary, upgradeProgress: { _ in }) self.database = self.openDatabase(encryptionParameters: self.encryptionParameters, isTemporary: self.isTemporary, isReadOnly: false, upgradeProgress: { _ in })
tables.removeAll() tables.removeAll()
} }
@ -2119,6 +2152,10 @@ public final class SqliteValueBox: ValueBox {
} }
private func reencryptInPlace(database: Database, encryptionParameters: ValueBoxEncryptionParameters) -> Database { private func reencryptInPlace(database: Database, encryptionParameters: ValueBoxEncryptionParameters) -> Database {
if self.isReadOnly {
preconditionFailure()
}
let targetPath = self.basePath + "/db_export" let targetPath = self.basePath + "/db_export"
let _ = try? FileManager.default.removeItem(atPath: targetPath) let _ = try? FileManager.default.removeItem(atPath: targetPath)
@ -2130,7 +2167,7 @@ public final class SqliteValueBox: ValueBox {
} }
let _ = try? FileManager.default.removeItem(atPath: targetPath) let _ = try? FileManager.default.removeItem(atPath: targetPath)
let updatedDatabase = Database(self.databasePath)! let updatedDatabase = Database(self.databasePath, readOnly: false)!
var resultCode = updatedDatabase.execute("PRAGMA cipher_plaintext_header_size=32") var resultCode = updatedDatabase.execute("PRAGMA cipher_plaintext_header_size=32")
assert(resultCode) assert(resultCode)

View File

@ -73,9 +73,9 @@ public enum AccountTransactionError {
case couldNotOpen case couldNotOpen
} }
public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, AccountTransactionError> { public func accountTransaction<T>(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, isReadOnly: Bool, transaction: @escaping (Postbox, Transaction) -> T) -> Signal<T, AccountTransactionError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true) let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: isReadOnly)
return postbox return postbox
|> castError(AccountTransactionError.self) |> castError(AccountTransactionError.self)
|> mapToSignal { value -> Signal<T, AccountTransactionError> in |> mapToSignal { value -> Signal<T, AccountTransactionError> in

View File

@ -160,7 +160,7 @@ public enum AccountPreferenceEntriesResult {
public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set<ValueBoxKey>, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountPreferenceEntriesResult, NoError> { public func accountPreferenceEntries(rootPath: String, id: AccountRecordId, keys: Set<ValueBoxKey>, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountPreferenceEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true) let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true)
return postbox return postbox
|> mapToSignal { value -> Signal<AccountPreferenceEntriesResult, NoError> in |> mapToSignal { value -> Signal<AccountPreferenceEntriesResult, NoError> in
switch value { switch value {
@ -189,7 +189,7 @@ public enum AccountNoticeEntriesResult {
public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountNoticeEntriesResult, NoError> { public func accountNoticeEntries(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<AccountNoticeEntriesResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true) let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true)
return postbox return postbox
|> mapToSignal { value -> Signal<AccountNoticeEntriesResult, NoError> in |> mapToSignal { value -> Signal<AccountNoticeEntriesResult, NoError> in
switch value { switch value {
@ -212,7 +212,7 @@ public enum LegacyAccessChallengeDataResult {
public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<LegacyAccessChallengeDataResult, NoError> { public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<LegacyAccessChallengeDataResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true) let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: true, isReadOnly: true)
return postbox return postbox
|> mapToSignal { value -> Signal<LegacyAccessChallengeDataResult, NoError> in |> mapToSignal { value -> Signal<LegacyAccessChallengeDataResult, NoError> in
switch value { switch value {
@ -231,7 +231,7 @@ public func accountLegacyAccessChallengeData(rootPath: String, id: AccountRecord
public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> { public func accountWithId(accountManager: AccountManager, networkArguments: NetworkInitializationArguments, id: AccountRecordId, encryptionParameters: ValueBoxEncryptionParameters, supplementary: Bool, rootPath: String, beginWithTestingEnvironment: Bool, backupData: AccountBackupData?, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false) let postbox = openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false)
return postbox return postbox
|> mapToSignal { result -> Signal<AccountResult, NoError> in |> mapToSignal { result -> Signal<AccountResult, NoError> in

View File

@ -214,7 +214,7 @@ public func temporaryAccount(manager: AccountManager, rootPath: String, encrypti
return manager.allocatedTemporaryAccountId() return manager.allocatedTemporaryAccountId()
|> mapToSignal { id -> Signal<TemporaryAccount, NoError> in |> mapToSignal { id -> Signal<TemporaryAccount, NoError> in
let path = "\(rootPath)/\(accountRecordIdPathName(id))" let path = "\(rootPath)/\(accountRecordIdPathName(id))"
return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false) return openPostbox(basePath: path + "/postbox", seedConfiguration: telegramPostboxSeedConfiguration, encryptionParameters: encryptionParameters, timestampForAbsoluteTimeBasedOperations: Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970), isTemporary: false, isReadOnly: false)
|> mapToSignal { result -> Signal<TemporaryAccount, NoError> in |> mapToSignal { result -> Signal<TemporaryAccount, NoError> in
switch result { switch result {
case .upgrading: case .upgrading:

View File

@ -664,7 +664,7 @@ final class SharedApplicationContext {
}) })
let accountManagerSignal = Signal<AccountManager, NoError> { subscriber in let accountManagerSignal = Signal<AccountManager, NoError> { subscriber in
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: false) let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false)
return (upgradedAccounts(accountManager: accountManager, rootPath: rootPath, encryptionParameters: encryptionParameters) return (upgradedAccounts(accountManager: accountManager, rootPath: rootPath, encryptionParameters: encryptionParameters)
|> deliverOnMainQueue).start(next: { progress in |> deliverOnMainQueue).start(next: { progress in
if self.dataImportSplash == nil { if self.dataImportSplash == nil {

View File

@ -113,7 +113,7 @@ public final class NotificationViewControllerImpl {
if sharedAccountContext == nil { if sharedAccountContext == nil {
initializeAccountManagement() initializeAccountManagement()
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true) let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings? var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
let semaphore = DispatchSemaphore(value: 0) let semaphore = DispatchSemaphore(value: 0)

View File

@ -202,7 +202,7 @@ public class ShareRootControllerImpl {
let internalContext: InternalContext let internalContext: InternalContext
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true) let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false)
if let globalInternalContext = globalInternalContext { if let globalInternalContext = globalInternalContext {
internalContext = globalInternalContext internalContext = globalInternalContext

View File

@ -290,7 +290,7 @@ public func upgradedAccounts(accountManager: AccountManager, rootPath: String, e
|> mapToSignal { globalSettings, ids -> Signal<Never, NoError> in |> mapToSignal { globalSettings, ids -> Signal<Never, NoError> in
var importSignal: Signal<Never, NoError> = .complete() var importSignal: Signal<Never, NoError> = .complete()
for id in ids { for id in ids {
let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, transaction: { _, transaction -> Void in let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, encryptionParameters: encryptionParameters, isReadOnly: false, transaction: { _, transaction -> Void in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts