Removed all the old Storage classes and YapDB extensions

Removed the AppUpdateNag code (unused)
Removed the Mantle dependency
This commit is contained in:
Morgan Pretty 2022-06-01 17:41:20 +10:00
parent 18d833f152
commit 59696f7d2c
56 changed files with 75 additions and 3764 deletions

View File

@ -1,17 +1,6 @@
import Foundation
import SessionUtilitiesKit
@objc
public final class SNMessagingKitConfiguration : NSObject {
public let storage: SessionMessagingKitStorageProtocol
@objc public static var shared: SNMessagingKitConfiguration!
fileprivate init(storage: SessionMessagingKitStorageProtocol) {
self.storage = storage
}
}
public enum SNMessagingKit { // Just to make the external API nice
public static func migrations() -> TargetMigrations {
return TargetMigrations(
@ -28,7 +17,7 @@ public enum SNMessagingKit { // Just to make the external API nice
)
}
public static func configure(storage: SessionMessagingKitStorageProtocol) {
public static func configure() {
// Configure the job executors
JobRunner.add(executor: DisappearingMessagesJob.self, for: .disappearingMessages)
JobRunner.add(executor: FailedMessageSendsJob.self, for: .failedMessageSends)
@ -42,7 +31,5 @@ public enum SNMessagingKit { // Just to make the external API nice
JobRunner.add(executor: SendReadReceiptsJob.self, for: .sendReadReceipts)
JobRunner.add(executor: AttachmentDownloadJob.self, for: .attachmentDownload)
JobRunner.add(executor: AttachmentUploadJob.self, for: .attachmentUpload)
SNMessagingKitConfiguration.shared = SNMessagingKitConfiguration(storage: storage)
}
}

View File

@ -21,7 +21,6 @@ abstract_target 'GlobalDependencies' do
pod 'PureLayout', '~> 3.1.8'
pod 'NVActivityIndicatorView'
pod 'YYImage', git: 'https://github.com/signalapp/YYImage'
pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master'
pod 'ZXingObjC'
pod 'DifferenceKit'
end
@ -38,7 +37,6 @@ abstract_target 'GlobalDependencies' do
abstract_target 'ExtendedDependencies' do
pod 'AFNetworking'
pod 'PureLayout', '~> 3.1.8'
pod 'Mantle', git: 'https://github.com/signalapp/Mantle', branch: 'signal-master'
target 'SessionShareExtension' do
pod 'NVActivityIndicatorView'

View File

@ -29,9 +29,6 @@ PODS:
- DifferenceKit/Core
- GRDB.swift/SQLCipher (5.24.1):
- SQLCipher (>= 3.4.0)
- Mantle (2.1.0):
- Mantle/extobjc (= 2.1.0)
- Mantle/extobjc (2.1.0)
- NVActivityIndicatorView (5.1.1):
- NVActivityIndicatorView/Base (= 5.1.1)
- NVActivityIndicatorView/Base (5.1.1)
@ -133,7 +130,6 @@ DEPENDENCIES:
- Curve25519Kit (from `https://github.com/signalapp/Curve25519Kit.git`)
- DifferenceKit
- GRDB.swift/SQLCipher
- Mantle (from `https://github.com/signalapp/Mantle`, branch `signal-master`)
- NVActivityIndicatorView
- PromiseKit
- PureLayout (~> 3.1.8)
@ -168,9 +164,6 @@ SPEC REPOS:
EXTERNAL SOURCES:
Curve25519Kit:
:git: https://github.com/signalapp/Curve25519Kit.git
Mantle:
:branch: signal-master
:git: https://github.com/signalapp/Mantle
SignalCoreKit:
:branch: session-version
:git: https://github.com/oxen-io/session-ios-core-kit
@ -184,9 +177,6 @@ CHECKOUT OPTIONS:
Curve25519Kit:
:commit: 4fc1c10e98fff2534b5379a9bb587430fdb8e577
:git: https://github.com/signalapp/Curve25519Kit.git
Mantle:
:commit: e7e46253bb01ce39525d90aa69ed9e85e758bfc4
:git: https://github.com/signalapp/Mantle
SignalCoreKit:
:commit: 4590c2737a2b5dc0ef4ace9f9019b581caccc1de
:git: https://github.com/oxen-io/session-ios-core-kit
@ -204,7 +194,6 @@ SPEC CHECKSUMS:
Curve25519Kit: e63f9859ede02438ae3defc5e1a87e09d1ec7ee6
DifferenceKit: 5659c430bb7fe45876fa32ce5cba5d6167f0c805
GRDB.swift: b3180ce2135fc06a453297889b746b1478c4d8c7
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
NVActivityIndicatorView: 1f6c5687f1171810aa27a3296814dc2d7dec3667
OpenSSL-Universal: e7311447fd2419f57420c79524b641537387eff2
PromiseKit: 3b2b6995e51a954c46dbc550ce3da44fbfb563c5
@ -219,6 +208,6 @@ SPEC CHECKSUMS:
YYImage: f1ddd15ac032a58b78bbed1e012b50302d318331
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
PODFILE CHECKSUM: 9715c163fab54d487be0c32357d6d1729aa96a7b
PODFILE CHECKSUM: 05dc0000aee6d863406fc684884935594fcf14fa
COCOAPODS: 1.11.2

View File

@ -107,7 +107,6 @@
4C9CA25D217E676900607C63 /* ZXingObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C9CA25C217E676900607C63 /* ZXingObjC.framework */; };
4CA46F4C219CCC630038ABDE /* CaptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA46F4B219CCC630038ABDE /* CaptionView.swift */; };
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; };
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; };
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; };
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
@ -176,8 +175,6 @@
B879D449247E1BE300DB3608 /* PathVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B879D448247E1BE300DB3608 /* PathVC.swift */; };
B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF17026367CF800124B3C /* FileServerAPIV2.swift */; };
B87EF18126377A1D00124B3C /* Features.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87EF18026377A1D00124B3C /* Features.swift */; };
B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB07255A580700E217F9 /* OWSBackupFragment.m */; };
B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */; };
B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */; };
@ -194,7 +191,6 @@
B8856DF8256F1633001CE70E /* NSString+SSK.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB12255A580800E217F9 /* NSString+SSK.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856E09256F1676001CE70E /* UIDevice+featureSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */; };
B8856E1A256F1700001CE70E /* OWSMath.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB14255A580800E217F9 /* OWSMath.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8856ECE256F1E58001CE70E /* OWSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF308255B6DBE007E1867 /* OWSPreferences.m */; };
B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2F1255B6DBB007E1867 /* OWSPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };
B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B886B4A62398B23E00211ABE /* QRCodeVC.swift */; };
@ -276,8 +272,6 @@
C32C5B51256DC219003C73A2 /* NSNotificationCenter+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB75255A581000E217F9 /* AppReadiness.m */; };
C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB01255A580700E217F9 /* AppReadiness.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */; };
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */; };
C32C5D19256DD493003C73A2 /* LinkPreviewDraft.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* LinkPreviewDraft.swift */; };
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */; };
C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */; };
@ -286,16 +280,6 @@
C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; };
C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB68255A580F00E217F9 /* ContentProxy.swift */; };
C32C5E0C256DDAFA003C73A2 /* NSRegularExpression+SSK.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */; };
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAB1255A580000E217F9 /* OWSStorage.m */; };
C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */; };
C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */; };
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */; };
C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB46255A580C00E217F9 /* TSDatabaseView.m */; };
C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */; };
C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */; };
@ -331,7 +315,6 @@
C33FD9C2255A54EF00E217F9 /* SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A6F025539DE700C340D1 /* SessionMessagingKit.framework */; };
C33FD9C4255A54EF00E217F9 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
C33FD9C5255A54EF00E217F9 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; };
C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */; };
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */; };
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; };
C33FDC50255A582000E217F9 /* OWSDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDA96255A57FE00E217F9 /* OWSDispatch.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -475,8 +458,6 @@
C3A01E05261D24C400290BEB /* public-loki-foundation.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E02261D24C400290BEB /* public-loki-foundation.der */; };
C3A01E06261D24C400290BEB /* storage-seed-1.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E03261D24C400290BEB /* storage-seed-1.der */; };
C3A01E07261D24C400290BEB /* storage-seed-3.der in Resources */ = {isa = PBXBuildFile; fileRef = C3A01E04261D24C400290BEB /* storage-seed-3.der */; };
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; };
C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */; };
C3A71D0B2558989C0043A11F /* MessageWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D0A2558989C0043A11F /* MessageWrapper.swift */; };
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A71D1C25589AC30043A11F /* WebSocketProto.swift */; };
@ -490,7 +471,6 @@
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AAFFF125AE99710089E6DD /* AppDelegate.swift */; };
C3ADC66126426688005F1414 /* ShareVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ADC66026426688005F1414 /* ShareVC.swift */; };
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE07F2554CDD70050F1E3 /* Storage.swift */; };
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; };
C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D92553860B00C340D1 /* JSON.swift */; };
C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BC255385EE00C340D1 /* HTTP.swift */; };
@ -539,10 +519,6 @@
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBAB255A581500E217F9 /* OWSFileSystem.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB85255A581100E217F9 /* AppContext.m */; };
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */; };
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB36255A580B00E217F9 /* Storage.swift */; };
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */; };
C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E43025676D3D0040E4F3 /* Configuration.swift */; };
C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; };
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; };
@ -989,7 +965,6 @@
4C9CA25C217E676900607C63 /* ZXingObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ZXingObjC.framework; path = ThirdParty/Carthage/Build/iOS/ZXingObjC.framework; sourceTree = "<group>"; };
4CA46F4B219CCC630038ABDE /* CaptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptionView.swift; sourceTree = "<group>"; };
4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = "<group>"; };
4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = "<group>"; };
4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = "<group>"; };
5A3F440C6CC32A23AD67A2FD /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
5B7FDA4BA2DDFF4612600FB8 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SignalUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
@ -1147,7 +1122,6 @@
B8D0A26825E4A2C200C1835E /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
B8D84EA225DF745A005A043E /* LinkPreviewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewState.swift; sourceTree = "<group>"; };
B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandingAttachmentsButton.swift; sourceTree = "<group>"; };
B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+OpenGroups.swift"; sourceTree = "<group>"; };
B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = "<group>"; };
B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = "<group>"; };
@ -1190,62 +1164,44 @@
C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = "<group>"; };
C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = "<group>"; };
C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "YapDatabase+Promise.swift"; sourceTree = "<group>"; };
C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = "<group>"; };
C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Hexadecimal.swift"; sourceTree = "<group>"; };
C33FDA7A255A57FB00E217F9 /* NSRegularExpression+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSRegularExpression+SSK.swift"; sourceTree = "<group>"; };
C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicators.swift; sourceTree = "<group>"; };
C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseTransaction+OWS.h"; sourceTree = "<group>"; };
C33FDA8B255A57FD00E217F9 /* AppVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppVersion.m; sourceTree = "<group>"; };
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = "<group>"; };
C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSYapDatabaseObject.m; sourceTree = "<group>"; };
C33FDA96255A57FE00E217F9 /* OWSDispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSDispatch.h; sourceTree = "<group>"; };
C33FDA99255A57FE00E217F9 /* OutageDetection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutageDetection.swift; sourceTree = "<group>"; };
C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseDispatchQueue.swift; sourceTree = "<group>"; };
C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSYapDatabaseObject.h; sourceTree = "<group>"; };
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = "<group>"; };
C33FDAB1255A580000E217F9 /* OWSStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSStorage.m; sourceTree = "<group>"; };
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OWSStorage+Subclass.h"; sourceTree = "<group>"; };
C33FDABE255A580100E217F9 /* TSConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSConstants.m; sourceTree = "<group>"; };
C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = "<group>"; };
C33FDADE255A580400E217F9 /* SwiftSingletons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSingletons.swift; sourceTree = "<group>"; };
C33FDAE0255A580400E217F9 /* ByteParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ByteParser.m; sourceTree = "<group>"; };
C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupFragment.h; sourceTree = "<group>"; };
C33FDAEF255A580500E217F9 /* NSData+Image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Image.m"; sourceTree = "<group>"; };
C33FDAF1255A580500E217F9 /* ThumbnailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailService.swift; sourceTree = "<group>"; };
C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxiedContentDownloader.swift; sourceTree = "<group>"; };
C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = "<group>"; };
C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = "<group>"; };
C33FDB01255A580700E217F9 /* AppReadiness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppReadiness.h; sourceTree = "<group>"; };
C33FDB07255A580700E217F9 /* OWSBackupFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackupFragment.m; sourceTree = "<group>"; };
C33FDB12255A580800E217F9 /* NSString+SSK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SSK.h"; sourceTree = "<group>"; };
C33FDB14255A580800E217F9 /* OWSMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMath.h; sourceTree = "<group>"; };
C33FDB17255A580800E217F9 /* FunctionalUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtil.m; sourceTree = "<group>"; };
C33FDB1C255A580900E217F9 /* UIImage+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+OWS.h"; sourceTree = "<group>"; };
C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = "<group>"; };
C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = "<group>"; };
C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = "<group>"; };
C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = "<group>"; };
C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseView.h; sourceTree = "<group>"; };
C33FDB34255A580B00E217F9 /* ClosedGroupPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosedGroupPoller.swift; sourceTree = "<group>"; };
C33FDB36255A580B00E217F9 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackgroundTask.h; sourceTree = "<group>"; };
C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = "<group>"; };
C33FDB3B255A580B00E217F9 /* NSNotificationCenter+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OWS.h"; sourceTree = "<group>"; };
C33FDB3F255A580C00E217F9 /* String+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SSK.swift"; sourceTree = "<group>"; };
C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOSProto.swift; sourceTree = "<group>"; };
C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = "<group>"; };
C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseConnection+OWS.m"; sourceTree = "<group>"; };
C33FDB45255A580C00E217F9 /* NSString+SSK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SSK.m"; sourceTree = "<group>"; };
C33FDB46255A580C00E217F9 /* TSDatabaseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseView.m; sourceTree = "<group>"; };
C33FDB49255A580C00E217F9 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
C33FDB4C255A580D00E217F9 /* AppVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppVersion.h; sourceTree = "<group>"; };
C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+OWS.h"; sourceTree = "<group>"; };
C33FDB54255A580D00E217F9 /* DataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataSource.h; sourceTree = "<group>"; };
C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YapDatabaseTransaction+OWS.m"; sourceTree = "<group>"; };
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YapDatabaseConnection+OWS.h"; sourceTree = "<group>"; };
C33FDB68255A580F00E217F9 /* ContentProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentProxy.swift; sourceTree = "<group>"; };
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = "<group>"; };
C33FDB6B255A580F00E217F9 /* SNUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SNUserDefaults.swift; sourceTree = "<group>"; };
@ -1272,7 +1228,6 @@
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = "<group>"; };
C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = "<group>"; };
C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = "<group>"; };
C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSPrimaryStorage.m; sourceTree = "<group>"; };
C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = "<group>"; };
C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = "<group>"; };
C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = "<group>"; };
@ -1426,7 +1381,6 @@
C3ADC66026426688005F1414 /* ShareVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareVC.swift; sourceTree = "<group>"; };
C3AECBEA24EF5244005743DE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = "<group>"; };
C3BBE0752554CDA60050F1E3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
C3BBE07F2554CDD70050F1E3 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FixedWidthInteger+BigEndian.swift"; sourceTree = "<group>"; };
C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SessionSnodeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SessionSnodeKit.h; sourceTree = "<group>"; };
@ -1472,7 +1426,6 @@
C3CA3ABD255CDB0D00F4C6D4 /* portuguese.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = portuguese.txt; sourceTree = "<group>"; };
C3CA3AC7255CDB2900F4C6D4 /* spanish.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = spanish.txt; sourceTree = "<group>"; };
C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundPoller.swift; sourceTree = "<group>"; };
C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSPrimaryStorageProtocol.swift; sourceTree = "<group>"; };
C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationMessage.swift; sourceTree = "<group>"; };
C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = "<group>"; };
@ -1487,7 +1440,6 @@
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Shared.swift"; sourceTree = "<group>"; };
C5060C3B36A848B71CCE4685 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C88965DE4F4EC4FC919BEC4E /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = "<group>"; };
C98441E849C3CA7FE8220D33 /* Pods-SessionNotificationServiceExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionNotificationServiceExtension.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionNotificationServiceExtension/Pods-SessionNotificationServiceExtension.app store release.xcconfig"; sourceTree = "<group>"; };
@ -1852,7 +1804,6 @@
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */,
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */,
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */,
4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */,
FD848B9728422F1A000E298B /* Date+Utilities.swift */,
FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */,
4C21D5D5223A9DC500EF8A77 /* UIAlerts+iOS9.m */,
@ -2081,11 +2032,7 @@
FD28A4F527EAD44C00FF65E7 /* GRDBStorage.swift */,
C33FDBAB255A581500E217F9 /* OWSFileSystem.h */,
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */,
C3D9E41E25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift */,
C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */,
C33FDB36255A580B00E217F9 /* Storage.swift */,
C33FDAA1255A57FF00E217F9 /* TSYapDatabaseObject.h */,
C33FDA90255A57FD00E217F9 /* TSYapDatabaseObject.m */,
);
path = Database;
sourceTree = "<group>";
@ -2385,19 +2332,6 @@
FD17D79427F3E03300122BE0 /* Migrations */,
FD09796C27FA6C8B00936362 /* Models */,
B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */,
C33FDAEA255A580500E217F9 /* OWSBackupFragment.h */,
C33FDB07255A580700E217F9 /* OWSBackupFragment.m */,
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */,
C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */,
C33FDAFE255A580600E217F9 /* OWSStorage.h */,
C33FDAB1255A580000E217F9 /* OWSStorage.m */,
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */,
B8D8F18825661BA50092EF10 /* Storage+OpenGroups.swift */,
C3F0A5FD255C988A007BE2A3 /* Storage+Shared.swift */,
C33FDB25255A580900E217F9 /* TSDatabaseSecondaryIndexes.h */,
C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */,
C33FDB2C255A580A00E217F9 /* TSDatabaseView.h */,
C33FDB46255A580C00E217F9 /* TSDatabaseView.m */,
);
path = Database;
sourceTree = "<group>";
@ -2475,7 +2409,6 @@
children = (
C33FD9B7255A54A300E217F9 /* Meta */,
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */,
C38BBA0E255E32440041B9A3 /* Database */,
C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */,
C38BBA0D255E321C0041B9A3 /* Messaging */,
C36096EF25AD2268008B62B2 /* Profile Pictures */,
@ -2704,13 +2637,6 @@
path = Notifications;
sourceTree = "<group>";
};
C379DCE82567330E0002D4EB /* Migrations */ = {
isa = PBXGroup;
children = (
);
path = Migrations;
sourceTree = "<group>";
};
C379DCE9256733390002D4EB /* Image Editing */ = {
isa = PBXGroup;
children = (
@ -2777,15 +2703,6 @@
path = Messaging;
sourceTree = "<group>";
};
C38BBA0E255E32440041B9A3 /* Database */ = {
isa = PBXGroup;
children = (
C379DCE82567330E0002D4EB /* Migrations */,
C33FDA6D255A57FA00E217F9 /* YapDatabase+Promise.swift */,
);
path = Database;
sourceTree = "<group>";
};
C3A721332558BDDF0043A11F /* Open Groups */ = {
isa = PBXGroup;
children = (
@ -2836,10 +2753,6 @@
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */,
C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */,
C3ECBF7A257056B700EA7FCE /* Threading.swift */,
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */,
C33FDB43255A580C00E217F9 /* YapDatabaseConnection+OWS.m */,
C33FDA88255A57FD00E217F9 /* YapDatabaseTransaction+OWS.h */,
C33FDB5B255A580E00E217F9 /* YapDatabaseTransaction+OWS.m */,
);
path = Utilities;
sourceTree = "<group>";
@ -2916,7 +2829,6 @@
children = (
C3C2A7802553AA6300C340D1 /* Protos */,
C3C2A70A25539DF900C340D1 /* Meta */,
C3BBE07F2554CDD70050F1E3 /* Storage.swift */,
C32C5BCB256DC818003C73A2 /* Database */,
C300A5BB2554AFFB00555489 /* Messages */,
C300A5F02554B08500555489 /* Sending & Receiving */,
@ -3497,7 +3409,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */,
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */,
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */,
C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */,
@ -3520,21 +3431,13 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C32C5EE5256DF506003C73A2 /* YapDatabaseConnection+OWS.h in Headers */,
C3C2A6F425539DE700C340D1 /* SessionMessagingKit.h in Headers */,
C32C5C46256DCBB2003C73A2 /* AppReadiness.h in Headers */,
B8856CB1256F0F47001CE70E /* OWSBackupFragment.h in Headers */,
C3A3A12B256E1AD5004D228D /* TSDatabaseSecondaryIndexes.h in Headers */,
C32C5FC4256E0209003C73A2 /* OWSBackgroundTask.h in Headers */,
C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */,
B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */,
C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */,
B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */,
B8856CF7256F105E001CE70E /* OWSAudioPlayer.h in Headers */,
C32C5E7E256DE023003C73A2 /* YapDatabaseTransaction+OWS.h in Headers */,
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */,
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */,
C32C5E64256DDFD6003C73A2 /* OWSStorage.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -4295,7 +4198,6 @@
C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */,
C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */,
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */,
C33FDC27255A581F00E217F9 /* YapDatabase+Promise.swift in Sources */,
C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */,
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
@ -4354,7 +4256,6 @@
7B1D74AC27BDE7510030B423 /* Promise+Timeout.swift in Sources */,
C3AABDDF2553ECF00042FF4C /* Array+Utilities.swift in Sources */,
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */,
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */,
7B1D74B027C365960030B423 /* Timer+MainThread.swift in Sources */,
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */,
C3D9E39B256763C20040E4F3 /* AppContext.m in Sources */,
@ -4393,7 +4294,6 @@
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */,
FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */,
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */,
C352A3A62557B60D00338F3E /* TSRequest.m in Sources */,
FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */,
FD09796B27F6C67500936362 /* Failable.swift in Sources */,
@ -4415,7 +4315,6 @@
B8BC00C0257D90E30032E807 /* General.swift in Sources */,
FD17D7A127F40D2500122BE0 /* GRDBStorage.swift in Sources */,
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */,
C3D9E41F25676C870040E4F3 /* OWSPrimaryStorageProtocol.swift in Sources */,
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */,
B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */,
FD17D7B027F4225C00122BE0 /* Set+Utilities.swift in Sources */,
@ -4478,11 +4377,9 @@
FDF0B7472804F0CE004C14C5 /* DisappearingMessagesJob.swift in Sources */,
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */,
C3D9E52725677DF20040E4F3 /* ThumbnailService.swift in Sources */,
C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */,
FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */,
FD09797527FAB64300936362 /* ProfileManager.swift in Sources */,
FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */,
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */,
C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */,
C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */,
FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */,
@ -4513,18 +4410,14 @@
C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */,
C32C5D19256DD493003C73A2 /* LinkPreviewDraft.swift in Sources */,
FD3C907527E83AC200CD579F /* OpenGroupServerIdLookup.swift in Sources */,
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */,
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */,
FDF0B7582807F368004C14C5 /* MessageReceiverError.swift in Sources */,
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */,
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */,
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */,
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */,
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */,
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */,
FD09798D27FD1D8900936362 /* DisappearingMessageConfiguration.swift in Sources */,
FDF0B75A2807F3A3004C14C5 /* MessageSenderError.swift in Sources */,
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */,
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */,
B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */,
C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */,
@ -4535,12 +4428,10 @@
C34A977425A3E34A00852C71 /* ClosedGroupControlMessage.swift in Sources */,
FD09799527FE7B8E00936362 /* Interaction.swift in Sources */,
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */,
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */,
C3A71D1F25589AC30043A11F /* WebSocketResources.pb.swift in Sources */,
FDF0B74B28061F7A004C14C5 /* InteractionAttachment.swift in Sources */,
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */,
FD09796E27FA6D0000936362 /* Contact.swift in Sources */,
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */,
C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */,
C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */,
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
@ -4553,14 +4444,12 @@
C3C2A75F2553A3C500C340D1 /* VisibleMessage+LinkPreview.swift in Sources */,
C32C5FBB256E0206003C73A2 /* OWSBackgroundTask.m in Sources */,
FD848B8D283E0B26000E298B /* MessageInputTypes.swift in Sources */,
B8856CA8256F0F42001CE70E /* OWSBackupFragment.m in Sources */,
C32C5C3D256DCBAF003C73A2 /* AppReadiness.m in Sources */,
B87EF17126367CF800124B3C /* FileServerAPIV2.swift in Sources */,
FD09799B27FFC82D00936362 /* Quote.swift in Sources */,
C3C2A74425539EB700C340D1 /* Message.swift in Sources */,
FD09798527FD1A6500936362 /* ClosedGroupKeyPair.swift in Sources */,
C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */,
C32C5EEE256DF54E003C73A2 /* TSDatabaseView.m in Sources */,
C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */,
FD09797027FA6FF300936362 /* Profile.swift in Sources */,
FD09798B27FD1CFE00936362 /* Capability.swift in Sources */,
@ -4657,7 +4546,6 @@
B8F5F71A25F1B35C003BF8D4 /* MediaPlaceholderView.swift in Sources */,
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */,
C331FFF32558FF0300070591 /* PathStatusView.swift in Sources */,
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */,
B848A4C5269EAAA200617031 /* UserDetailsSheet.swift in Sources */,
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
B886B4A72398B23E00211ABE /* QRCodeVC.swift in Sources */,

View File

@ -11,7 +11,6 @@
#import <SignalCoreKit/NSDate+OWS.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SessionMessagingKit/OWSPrimaryStorage.h>
@import ContactsUI;
@import PromiseKit;
@ -27,8 +26,6 @@ CGFloat kIconViewLength = 24;
@property (nonatomic) BOOL isNoteToSelf;
@property (nonatomic) BOOL isClosedGroup;
@property (nonatomic) BOOL isOpenGroup;
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection;
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
@property (nonatomic) BOOL originalIsDisappearingMessagesEnabled;
@ -106,11 +103,6 @@ CGFloat kIconViewLength = 24;
object:nil];
}
- (YapDatabaseConnection *)editingDatabaseConnection
{
return [OWSPrimaryStorage sharedManager].dbReadWriteConnection;
}
- (void)configureWithThreadId:(NSString *)threadId threadName:(nullable NSString *)threadName isClosedGroup:(BOOL)isClosedGroup isOpenGroup:(BOOL)isOpenGroup isNoteToSelf:(BOOL)isNoteToSelf {
self.threadId = threadId;
self.threadName = threadName;

View File

@ -236,14 +236,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
private func verifyDBKeysAvailableBeforeBackgroundLaunch() {
guard UIApplication.shared.applicationState == .background else { return }
// Ensure both databases are accessible (as long as we are supporting the YDB migration
// we should keep this check)
let databasePasswordAccessible: Bool = (
GRDBStorage.isDatabasePasswordAccessible && // GRDB password access
OWSStorage.isDatabasePasswordAccessible() // YapDatabase password access
)
guard !databasePasswordAccessible else { return } // All good
guard !GRDBStorage.isDatabasePasswordAccessible else { return } // All good
Logger.info("Exiting because we are in the background and the database password is not accessible.")

View File

@ -57,9 +57,8 @@ public struct SessionApp {
Logger.error("")
DDLog.flushLog()
OWSStorage.resetAllStorage()
GRDBStorage.resetAllStorage()
ProfileManager.resetProfileStorage()
Environment.shared.preferences.clear()
AppEnvironment.shared.notificationPresenter.clearAllNotifications()
onReset?()

View File

@ -118,12 +118,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
SwiftSingletons.register(self)
}
// MARK: - Dependencies
var preferences: OWSPreferences {
return Environment.shared.preferences
}
// MARK: -
@objc
@ -380,10 +374,6 @@ class NotificationActionHandler {
return AppEnvironment.shared.notificationPresenter
}
var dbConnection: YapDatabaseConnection {
return OWSPrimaryStorage.shared().dbReadWriteConnection
}
// MARK: -
func markAsRead(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {

View File

@ -1,243 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation
import PromiseKit
@objc
class AppUpdateNag: NSObject {
// MARK: Public
@objc(sharedInstance)
public static let shared: AppUpdateNag = {
let versionService = AppStoreVersionService()
let nagManager = AppUpdateNag(versionService: versionService)
return nagManager
}()
@objc
public func showAppUpgradeNagIfNecessary() {
return
/*
guard let currentVersion = self.currentVersion else {
owsFailDebug("currentVersion was unexpectedly nil")
return
}
guard let bundleIdentifier = self.bundleIdentifier else {
owsFailDebug("bundleIdentifier was unexpectedly nil")
return
}
guard let lookupURL = lookupURL(bundleIdentifier: bundleIdentifier) else {
owsFailDebug("appStoreURL was unexpectedly nil")
return
}
firstly {
self.versionService.fetchLatestVersion(lookupURL: lookupURL)
}.done { appStoreRecord in
guard appStoreRecord.version.compare(currentVersion, options: .numeric) == ComparisonResult.orderedDescending else {
Logger.debug("remote version: \(appStoreRecord) is not newer than currentVersion: \(currentVersion)")
return
}
Logger.info("new version available: \(appStoreRecord)")
self.showUpdateNagIfEnoughTimeHasPassed(appStoreRecord: appStoreRecord)
}.catch { error in
Logger.error("failed with error: \(error)")
}.retainUntilComplete()
*/
}
// MARK: - Internal
let kUpgradeNagCollection = "TSStorageManagerAppUpgradeNagCollection"
let kLastNagDateKey = "TSStorageManagerAppUpgradeNagDate"
let kFirstHeardOfNewVersionDateKey = "TSStorageManagerAppUpgradeFirstHeardOfNewVersionDate"
var dbConnection: YapDatabaseConnection {
return OWSPrimaryStorage.shared().dbReadWriteConnection
}
// MARK: Bundle accessors
var bundle: Bundle {
return Bundle.main
}
var currentVersion: String? {
return bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
}
var bundleIdentifier: String? {
return bundle.bundleIdentifier
}
func lookupURL(bundleIdentifier: String) -> URL? {
return URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleIdentifier)")
}
let versionService: AppStoreVersionService
required init(versionService: AppStoreVersionService) {
self.versionService = versionService
super.init()
SwiftSingletons.register(self)
}
func showUpdateNagIfEnoughTimeHasPassed(appStoreRecord: AppStoreRecord) {
guard let firstHeardOfNewVersionDate = self.firstHeardOfNewVersionDate else {
self.setFirstHeardOfNewVersionDate(Date())
return
}
let intervalBeforeNag = 7 * kDayInterval
guard Date() > Date.init(timeInterval: intervalBeforeNag, since: firstHeardOfNewVersionDate) else {
Logger.info("firstHeardOfNewVersionDate: \(firstHeardOfNewVersionDate) not nagging for new release yet.")
return
}
if let lastNagDate = self.lastNagDate {
let intervalBetweenNags = 14 * kDayInterval
guard Date() > Date.init(timeInterval: intervalBetweenNags, since: lastNagDate) else {
Logger.info("lastNagDate: \(lastNagDate) not nagging again so soon.")
return
}
}
// Only show nag if we are "at rest" in the home view or registration view without any
// alerts or dialogs showing.
guard UIApplication.shared.frontmostViewController != nil else {
owsFailDebug("frontmostViewController was unexpectedly nil")
return
}
/*
switch frontmostViewController {
case is OnboardingSplashViewController:
self.setLastNagDate(Date())
self.clearFirstHeardOfNewVersionDate()
presentUpgradeNag(appStoreRecord: appStoreRecord)
default:
Logger.debug("not presenting alert due to frontmostViewController: \(frontmostViewController)")
break
}
*/
}
func presentUpgradeNag(appStoreRecord: AppStoreRecord) {
let title = NSLocalizedString("APP_UPDATE_NAG_ALERT_TITLE", comment: "Title for the 'new app version available' alert.")
let bodyFormat = NSLocalizedString("APP_UPDATE_NAG_ALERT_MESSAGE_FORMAT", comment: "Message format for the 'new app version available' alert. Embeds: {{The latest app version number}}")
let bodyText = String(format: bodyFormat, appStoreRecord.version)
let updateButtonText = NSLocalizedString("APP_UPDATE_NAG_ALERT_UPDATE_BUTTON", comment: "Label for the 'update' button in the 'new app version available' alert.")
let dismissButtonText = NSLocalizedString("APP_UPDATE_NAG_ALERT_DISMISS_BUTTON", comment: "Label for the 'dismiss' button in the 'new app version available' alert.")
let alert = UIAlertController(title: title, message: bodyText, preferredStyle: .alert)
let updateAction = UIAlertAction(title: updateButtonText, style: .default) { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.showAppStore(appStoreURL: appStoreRecord.appStoreURL)
}
alert.addAction(updateAction)
alert.addAction(UIAlertAction(title: dismissButtonText, style: .cancel, handler: nil))
OWSAlerts.showAlert(alert)
}
func showAppStore(appStoreURL: URL) {
Logger.debug("")
UIApplication.shared.openURL(appStoreURL)
}
// MARK: Storage
var firstHeardOfNewVersionDate: Date? {
return self.dbConnection.date(forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
}
func setFirstHeardOfNewVersionDate(_ date: Date) {
self.dbConnection.setDate(date, forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
}
func clearFirstHeardOfNewVersionDate() {
self.dbConnection.removeObject(forKey: kFirstHeardOfNewVersionDateKey, inCollection: kUpgradeNagCollection)
}
var lastNagDate: Date? {
return self.dbConnection.date(forKey: kLastNagDateKey, inCollection: kUpgradeNagCollection)
}
func setLastNagDate(_ date: Date) {
self.dbConnection.setDate(date, forKey: kLastNagDateKey, inCollection: kUpgradeNagCollection)
}
}
// MARK: Parsing Structs
struct AppStoreLookupResultSet: Codable {
let resultCount: UInt
let results: [AppStoreRecord]
}
struct AppStoreRecord: Codable {
let appStoreURL: URL
let version: String
private enum CodingKeys: String, CodingKey {
case appStoreURL = "trackViewUrl"
case version
}
}
class AppStoreVersionService: NSObject {
// MARK:
func fetchLatestVersion(lookupURL: URL) -> Promise<AppStoreRecord> {
Logger.debug("lookupURL:\(lookupURL)")
let (promise, resolver) = Promise<AppStoreRecord>.pending()
let task = URLSession.ephemeral.dataTask(with: lookupURL) { (data, _, error) in
guard let data = data else {
Logger.warn("data was unexpectedly nil")
resolver.reject(OWSErrorMakeUnableToProcessServerResponseError())
return
}
do {
let decoder = JSONDecoder()
let resultSet = try decoder.decode(AppStoreLookupResultSet.self, from: data)
guard let appStoreRecord = resultSet.results.first else {
Logger.warn("record was unexpectedly nil")
resolver.reject(OWSErrorMakeUnableToProcessServerResponseError())
return
}
resolver.fulfill(appStoreRecord)
} catch {
resolver.reject(error)
}
}
task.resume()
return promise
}
}
extension URLSession {
static var ephemeral: URLSession {
return URLSession(configuration: .ephemeral)
}
}

View File

@ -3,6 +3,7 @@
import Foundation
import AVKit
import GRDB
import YapDatabase
import Curve25519Kit
import SessionUtilitiesKit
import SessionSnodeKit
@ -278,38 +279,49 @@ enum _003_YDBToGRDBMigration: Migration {
// Note: The 'int(forKey:inCollection:)' defaults to `0` which is an incorrect value
// for the notification sound so catch it and default
let globalNotificationSoundValue: Int32 = transaction.int(
forKey: SMKLegacy.soundsGlobalNotificationKey,
inCollection: SMKLegacy.soundsStorageNotificationCollection
)
legacyPreferences[SMKLegacy.soundsGlobalNotificationKey] = (globalNotificationSoundValue > 0 ?
Int(globalNotificationSoundValue) :
Preferences.Sound.defaultNotificationSound.rawValue
)
legacyPreferences[SMKLegacy.soundsGlobalNotificationKey] = (transaction
.object(
forKey: SMKLegacy.soundsGlobalNotificationKey,
inCollection: SMKLegacy.soundsStorageNotificationCollection
)
.asType(NSNumber.self)?
.intValue)
.defaulting(to: Preferences.Sound.defaultNotificationSound.rawValue)
legacyPreferences[SMKLegacy.readReceiptManagerAreReadReceiptsEnabled] = transaction.bool(
forKey: SMKLegacy.readReceiptManagerAreReadReceiptsEnabled,
inCollection: SMKLegacy.readReceiptManagerCollection,
defaultValue: false
)
legacyPreferences[SMKLegacy.readReceiptManagerAreReadReceiptsEnabled] = (transaction
.object(
forKey: SMKLegacy.readReceiptManagerAreReadReceiptsEnabled,
inCollection: SMKLegacy.readReceiptManagerCollection
)
.asType(NSNumber.self)?
.boolValue)
.defaulting(to: false)
legacyPreferences[SMKLegacy.typingIndicatorsEnabledKey] = transaction.bool(
forKey: SMKLegacy.typingIndicatorsEnabledKey,
inCollection: SMKLegacy.typingIndicatorsCollection,
defaultValue: false
)
legacyPreferences[SMKLegacy.typingIndicatorsEnabledKey] = (transaction
.object(
forKey: SMKLegacy.typingIndicatorsEnabledKey,
inCollection: SMKLegacy.typingIndicatorsCollection
)
.asType(NSNumber.self)?
.boolValue)
.defaulting(to: false)
legacyPreferences[SMKLegacy.screenLockIsScreenLockEnabledKey] = transaction.bool(
forKey: SMKLegacy.screenLockIsScreenLockEnabledKey,
inCollection: SMKLegacy.screenLockCollection,
defaultValue: false
)
legacyPreferences[SMKLegacy.screenLockIsScreenLockEnabledKey] = (transaction
.object(
forKey: SMKLegacy.screenLockIsScreenLockEnabledKey,
inCollection: SMKLegacy.screenLockCollection
)
.asType(NSNumber.self)?
.boolValue)
.defaulting(to: false)
legacyPreferences[SMKLegacy.screenLockScreenLockTimeoutSecondsKey] = transaction.double(
forKey: SMKLegacy.screenLockScreenLockTimeoutSecondsKey,
inCollection: SMKLegacy.screenLockCollection,
defaultValue: (15 * 60)
)
legacyPreferences[SMKLegacy.screenLockScreenLockTimeoutSecondsKey] = (transaction
.object(
forKey: SMKLegacy.screenLockScreenLockTimeoutSecondsKey,
inCollection: SMKLegacy.screenLockCollection)
.asType(NSNumber.self)?
.doubleValue)
.defaulting(to: (15 * 60))
GRDBStorage.shared.update(progress: 0.23, for: self, in: target)
}

View File

@ -1,7 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import SessionUtilitiesKit
// FIXME: Remove these extensions once the OWSConversationSettingsViewModel is refactored to swift and uses proper database observation
public extension Notification.Name {
static let otherUsersProfileDidChange = Notification.Name("otherUsersProfileDidChange")

View File

@ -1,44 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
NS_ASSUME_NONNULL_BEGIN
// We store metadata for known backup fragments (i.e. CloudKit record) in
// the database. We might learn about them from:
//
// * Past backup exports.
// * An import downloading and parsing the manifest of the last complete backup.
//
// Storing this data in the database provides continuity.
//
// * Backup exports can reuse fragments from previous Backup exports even if they
// don't complete (i.e. backup export resume).
// * Backup exports can reuse fragments from the backup import, if any.
@interface OWSBackupFragment : TSYapDatabaseObject
@property (nonatomic) NSString *recordName;
@property (nonatomic) NSData *encryptionKey;
// This property is only set for certain types of manifest item,
// namely attachments where we need to know where the attachment's
// file should reside relative to the attachments folder.
@property (nonatomic, nullable) NSString *relativeFilePath;
// This property is only set for attachments.
@property (nonatomic, nullable) NSString *attachmentId;
// This property is only set if the manifest item is downloaded.
@property (nonatomic, nullable) NSString *downloadFilePath;
// This property is only set if the manifest item is compressed.
@property (nonatomic, nullable) NSNumber *uncompressedDataLength;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,13 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSBackupFragment.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSBackupFragment
@end
NS_ASSUME_NONNULL_END

View File

@ -1,51 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <SessionMessagingKit/OWSStorage.h>
NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSUIDatabaseConnectionWillUpdateNotification;
extern NSString *const OWSUIDatabaseConnectionDidUpdateNotification;
extern NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification;
extern NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification;
extern NSString *const OWSUIDatabaseConnectionNotificationsKey;
@interface OWSPrimaryStorage : OWSStorage
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initStorage;
+ (instancetype)sharedManager NS_SWIFT_NAME(shared());
@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
- (void)updateUIDatabaseConnectionToLatest;
+ (YapDatabaseConnection *)dbReadConnection;
+ (YapDatabaseConnection *)dbReadWriteConnection;
+ (nullable NSError *)migrateToSharedData;
+ (NSString *)databaseFilePath;
+ (NSString *)legacyDatabaseFilePath;
+ (NSString *)legacyDatabaseFilePath_SHM;
+ (NSString *)legacyDatabaseFilePath_WAL;
+ (NSString *)sharedDataDatabaseFilePath;
+ (NSString *)sharedDataDatabaseFilePath_SHM;
+ (NSString *)sharedDataDatabaseFilePath_WAL;
+ (void)protectFiles;
#pragma mark - Misc.
- (void)touchDbAsync;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,382 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSPrimaryStorage.h"
#import "AppContext.h"
#import "OWSFileSystem.h"
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
#import "OWSStorage.h"
#import "OWSStorage+Subclass.h"
#import "TSDatabaseSecondaryIndexes.h"
#import "TSDatabaseView.h"
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
#import <YapDatabase/YapDatabaseConnectionPool.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const OWSUIDatabaseConnectionWillUpdateNotification = @"OWSUIDatabaseConnectionWillUpdateNotification";
NSString *const OWSUIDatabaseConnectionDidUpdateNotification = @"OWSUIDatabaseConnectionDidUpdateNotification";
NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification = @"OWSUIDatabaseConnectionWillUpdateExternallyNotification";
NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification = @"OWSUIDatabaseConnectionDidUpdateExternallyNotification";
NSString *const OWSUIDatabaseConnectionNotificationsKey = @"OWSUIDatabaseConnectionNotificationsKey";
void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
{
[[storage newDatabaseConnection] asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (NSString *extensionName in storage.registeredExtensionNames) {
YapDatabaseViewTransaction *_Nullable viewTransaction = [transaction ext:extensionName];
if (!viewTransaction) {
[OWSStorage incrementVersionOfDatabaseExtension:extensionName];
}
}
}];
}
#pragma mark -
@interface OWSPrimaryStorage ()
@property (atomic) BOOL areAsyncRegistrationsComplete;
@property (atomic) BOOL areSyncRegistrationsComplete;
@property (nonatomic, readonly) YapDatabaseConnectionPool *dbReadPool;
@end
#pragma mark -
@implementation OWSPrimaryStorage
@synthesize uiDatabaseConnection = _uiDatabaseConnection;
+ (instancetype)sharedManager
{
return SSKEnvironment.shared.primaryStorage;
}
- (instancetype)initStorage
{
self = [super initStorage];
if (self) {
[self loadDatabase];
_dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database];
_dbReadPool.connectionLimit = 10; // Increase max read connection limit. Default is 3.
_dbReadWriteConnection = [self newDatabaseConnection];
_uiDatabaseConnection = [self newDatabaseConnection];
// Increase object cache limit. Default is 250.
_uiDatabaseConnection.objectCacheLimit = 500;
[_uiDatabaseConnection beginLongLivedReadTransaction];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:self.dbNotificationObject];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
// Notify observers we're about to update the database connection
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateExternallyNotification object:self.dbNotificationObject];
// Move uiDatabaseConnection to the latest commit.
// Do so atomically, and fetch all the notifications for each commit we jump.
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
// Notify observers that the uiDatabaseConnection was updated
NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications };
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateExternallyNotification
object:self.dbNotificationObject
userInfo:userInfo];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
[self updateUIDatabaseConnectionToLatest];
}
- (void)updateUIDatabaseConnectionToLatest
{
// Notify observers we're about to update the database connection
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateNotification object:self.dbNotificationObject];
// Move uiDatabaseConnection to the latest commit.
// Do so atomically, and fetch all the notifications for each commit we jump.
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
// Notify observers that the uiDatabaseConnection was updated
NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications };
[[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateNotification
object:self.dbNotificationObject
userInfo:userInfo];
}
- (YapDatabaseConnection *)uiDatabaseConnection
{
return _uiDatabaseConnection;
}
- (void)resetStorage
{
_dbReadPool = nil;
_uiDatabaseConnection = nil;
_dbReadWriteConnection = nil;
[super resetStorage];
}
- (void)runSyncRegistrations
{
// Synchronously register extensions which are essential for views.
[TSDatabaseView registerCrossProcessNotifier:self];
// See comments on OWSDatabaseConnection.
//
// In the absence of finding documentation that can shed light on the issue we've been
// seeing, this issue only seems to affect sync and not async registrations. We've always
// been opening write transactions before the async registrations complete without negative
// consequences.
self.areSyncRegistrationsComplete = YES;
}
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion
{
// Asynchronously register other extensions.
//
// All sync registrations must be done before all async registrations,
// or the sync registrations will block on the async registrations.
[TSDatabaseView asyncRegisterLegacyThreadInteractionsDatabaseView:self];
[TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:self];
[TSDatabaseView asyncRegisterThreadDatabaseView:self];
[self asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex]
withName:[TSDatabaseSecondaryIndexes registerTimeStampIndexExtensionName]];
[TSDatabaseView asyncRegisterUnreadMentionDatabaseView:self];
[TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:self];
[FullTextSearchFinder asyncRegisterDatabaseExtensionWithStorage:self];
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self];
[self.database
flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
completionBlock:^{
self.areAsyncRegistrationsComplete = YES;
completion();
[self verifyDatabaseViews];
}];
}
- (void)verifyDatabaseViews
{
VerifyRegistrationsForPrimaryStorage(self);
}
+ (void)protectFiles
{
// Protect the entire new database directory.
[OWSFileSystem protectFileOrFolderAtPath:self.sharedDataDatabaseDirPath];
}
+ (NSString *)legacyDatabaseDirPath
{
return [OWSFileSystem appDocumentDirectoryPath];
}
+ (NSString *)sharedDataDatabaseDirPath
{
NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"];
[OWSFileSystem ensureDirectoryExists:databaseDirPath];
return databaseDirPath;
}
+ (NSString *)databaseFilename
{
return @"Signal.sqlite";
}
+ (NSString *)databaseFilename_SHM
{
return [self.databaseFilename stringByAppendingString:@"-shm"];
}
+ (NSString *)databaseFilename_WAL
{
return [self.databaseFilename stringByAppendingString:@"-wal"];
}
+ (NSString *)legacyDatabaseFilePath
{
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
}
+ (NSString *)legacyDatabaseFilePath_SHM
{
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
}
+ (NSString *)legacyDatabaseFilePath_WAL
{
return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
}
+ (NSString *)sharedDataDatabaseFilePath
{
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename];
}
+ (NSString *)sharedDataDatabaseFilePath_SHM
{
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM];
}
+ (NSString *)sharedDataDatabaseFilePath_WAL
{
return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL];
}
+ (nullable NSError *)migrateToSharedData
{
// Given how sensitive this migration is, we verbosely
// log the contents of all involved paths before and after.
NSFileManager *fileManager = [NSFileManager defaultManager];
// We protect the db files here, which is somewhat redundant with what will happen in
// `moveAppFilePath:` which also ensures file protection.
// However that method dispatches async, since it can take a while with large attachment directories.
//
// Since we only have three files here it'll be quick to do it sync, and we want to make
// sure it happens as part of the migration.
//
// FileProtection attributes move with the file, so we do it on the legacy files before moving
// them.
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath];
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_SHM];
[OWSFileSystem protectFileOrFolderAtPath:self.legacyDatabaseFilePath_WAL];
NSError *_Nullable error = nil;
if ([fileManager fileExistsAtPath:self.legacyDatabaseFilePath] &&
[fileManager fileExistsAtPath:self.sharedDataDatabaseFilePath]) {
// In the case that we have a "database conflict" (i.e. database files
// in the src and dst locations), ensure database integrity by renaming
// all of the dst database files.
for (NSString *filePath in @[
self.sharedDataDatabaseFilePath,
self.sharedDataDatabaseFilePath_SHM,
self.sharedDataDatabaseFilePath_WAL,
]) {
error = [OWSFileSystem renameFilePathUsingRandomExtension:filePath];
if (error) {
return error;
}
}
}
error =
[OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath sharedDataFilePath:self.sharedDataDatabaseFilePath];
if (error) {
return error;
}
error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM
sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM];
if (error) {
return error;
}
error = [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL
sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL];
if (error) {
return error;
}
return nil;
}
+ (NSString *)databaseFilePath
{
return self.sharedDataDatabaseFilePath;
}
+ (NSString *)databaseFilePath_SHM
{
return self.sharedDataDatabaseFilePath_SHM;
}
+ (NSString *)databaseFilePath_WAL
{
return self.sharedDataDatabaseFilePath_WAL;
}
- (NSString *)databaseFilePath
{
return OWSPrimaryStorage.databaseFilePath;
}
- (NSString *)databaseFilePath_SHM
{
return OWSPrimaryStorage.databaseFilePath_SHM;
}
- (NSString *)databaseFilePath_WAL
{
return OWSPrimaryStorage.databaseFilePath_WAL;
}
- (NSString *)databaseFilename_SHM
{
return OWSPrimaryStorage.databaseFilename_SHM;
}
- (NSString *)databaseFilename_WAL
{
return OWSPrimaryStorage.databaseFilename_WAL;
}
+ (YapDatabaseConnection *)dbReadConnection
{
return OWSPrimaryStorage.sharedManager.dbReadConnection;
}
- (YapDatabaseConnection *)dbReadConnection
{
return self.dbReadPool.connection;
}
+ (YapDatabaseConnection *)dbReadWriteConnection
{
return OWSPrimaryStorage.sharedManager.dbReadWriteConnection;
}
#pragma mark - Misc.
- (void)touchDbAsync
{
// There appears to be a bug in YapDatabase that sometimes delays modifications
// made in another process (e.g. the SAE) from showing up in other processes.
// There's a simple workaround: a trivial write to the database flushes changes
// made from other processes.
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction setObject:[NSUUID UUID].UUIDString forKey:@"conversation_view_noop_mod" inCollection:@"temp"];
}];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,32 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SessionMessagingKit/OWSStorage.h>
NS_ASSUME_NONNULL_BEGIN
@class YapDatabase;
@interface OWSStorage (Subclass)
@property (atomic, nullable, readonly) YapDatabase *database;
- (void)loadDatabase;
- (void)runSyncRegistrations;
// completion will be invoked _off_ the main thread.
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion;
- (BOOL)areAsyncRegistrationsComplete;
- (BOOL)areSyncRegistrationsComplete;
- (NSString *)databaseFilePath;
- (NSString *)databaseFilePath_SHM;
- (NSString *)databaseFilePath_WAL;
- (void)resetStorage;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,116 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <YapDatabase/YapDatabase.h>
NS_ASSUME_NONNULL_BEGIN
extern NSString *const StorageIsReadyNotification;
@class YapDatabaseExtension;
@protocol OWSDatabaseConnectionDelegate <NSObject>
- (BOOL)areAllRegistrationsComplete;
@end
#pragma mark -
@interface OWSDatabaseConnection : YapDatabaseConnection
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithDatabase:(YapDatabase *)database
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
@end
#pragma mark -
@interface OWSDatabase : YapDatabase
- (instancetype)init NS_UNAVAILABLE;
- (id)initWithPath:(NSString *)inPath
serializer:(nullable YapDatabaseSerializer)inSerializer
deserializer:(YapDatabaseDeserializer)inDeserializer
options:(YapDatabaseOptions *)inOptions
delegate:(id<OWSDatabaseConnectionDelegate>)delegate NS_DESIGNATED_INITIALIZER;
@end
#pragma mark -
typedef void (^OWSStorageMigrationBlock)(void);
@interface OWSStorage : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initStorage NS_DESIGNATED_INITIALIZER;
// Returns YES if _ALL_ storage classes have completed both their
// sync _AND_ async view registrations.
+ (BOOL)isStorageReady;
// This object can be used to filter database notifications.
@property (nonatomic, readonly, nullable) id dbNotificationObject;
// migrationBlock will be invoked _off_ the main thread.
+ (void)registerExtensionsWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock;
#ifdef DEBUG
- (void)closeStorageForTests;
#endif
+ (void)resetAllStorage;
- (YapDatabaseConnection *)newDatabaseConnection;
+ (YapDatabaseOptions *)defaultDatabaseOptions;
#pragma mark - Extension Registration
+ (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName;
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
withName:(NSString *)extensionName
completion:(nullable dispatch_block_t)completion;
- (nullable id)registeredExtension:(NSString *)extensionName;
- (NSArray<NSString *> *)registeredExtensionNames;
#pragma mark -
- (unsigned long long)databaseFileSize;
- (unsigned long long)databaseWALFileSize;
- (unsigned long long)databaseSHMFileSize;
- (YapDatabaseConnection *)registrationConnection;
#pragma mark - Password
/**
* Returns NO if:
*
* - Keychain is locked because device has just been restarted.
* - Password could not be retrieved because of a keychain error.
*/
+ (BOOL)isDatabasePasswordAccessible;
+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle;
+ (void)removeLegacyPassphrase;
+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData;
- (void)logFileSizes;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,808 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSStorage.h"
#import "AppContext.h"
#import "OWSBackgroundTask.h"
#import "OWSFileSystem.h"
#import "OWSPrimaryStorage.h"
#import "TSYapDatabaseObject.h"
#import <SignalCoreKit/SignalCoreKit.h>
#import <SignalCoreKit/Randomness.h>
#import <YapDatabase/YapDatabase.h>
#import <YapDatabase/YapDatabaseAutoView.h>
#import <YapDatabase/YapDatabaseCryptoUtils.h>
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
#import <YapDatabase/YapDatabaseFullTextSearch.h>
#import <YapDatabase/YapDatabaseFullTextSearchPrivate.h>
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
#import <YapDatabase/YapDatabaseSecondaryIndexPrivate.h>
#import <YapDatabase/YapDatabaseSecondaryIndexSetup.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
#import <SessionUtilitiesKit/AppContext.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const StorageIsReadyNotification = @"StorageIsReadyNotification";
NSString *const OWSResetStorageNotification = @"OWSResetStorageNotification";
static NSString *keychainService = @"TSKeyChainService";
static NSString *keychainDBLegacyPassphrase = @"TSDatabasePass";
static NSString *keychainDBCipherKeySpec = @"OWSDatabaseCipherKeySpec";
const NSUInteger kDatabasePasswordLength = 30;
typedef NSData *_Nullable (^LoadDatabaseMetadataBlock)(NSError **_Nullable);
typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_DatabaseExtensionVersionMap";
#pragma mark -
@interface YapDatabaseConnection ()
- (id)initWithDatabase:(YapDatabase *)database;
@end
#pragma mark -
@implementation OWSDatabaseConnection
- (id)initWithDatabase:(YapDatabase *)database delegate:(id<OWSDatabaseConnectionDelegate>)delegate
{
self = [super initWithDatabase:database];
if (!self) {
return self;
}
self.delegate = delegate;
return self;
}
// Assert that the database is in a ready state (specifically that any sync database
// view registrations have completed and any async registrations have been started)
// before creating write transactions.
//
// Creating write transactions before the _sync_ database views are registered
// causes YapDatabase to rebuild all of our database views, which is catastrophic.
// Specifically, it causes YDB's "view version" checks to fail.
- (void)readWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
{
OWSBackgroundTask *_Nullable backgroundTask = nil;
if (CurrentAppContext().isMainApp && !CurrentAppContext().isRunningTests) {
backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
}
[super readWriteWithBlock:block];
backgroundTask = nil;
}
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
{
[self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:NULL];
}
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
completionBlock:(nullable dispatch_block_t)completionBlock
{
[self asyncReadWriteWithBlock:block completionQueue:NULL completionBlock:completionBlock];
}
- (void)asyncReadWriteWithBlock:(void (^)(YapDatabaseReadWriteTransaction *transaction))block
completionQueue:(nullable dispatch_queue_t)completionQueue
completionBlock:(nullable dispatch_block_t)completionBlock
{
__block OWSBackgroundTask *_Nullable backgroundTask = nil;
if (CurrentAppContext().isMainApp) {
backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
}
[super asyncReadWriteWithBlock:block completionQueue:completionQueue completionBlock:^{
if (completionBlock) {
completionBlock();
}
backgroundTask = nil;
}];
}
@end
#pragma mark -
// This class is only used in DEBUG builds.
@interface YapDatabase ()
- (void)addConnection:(YapDatabaseConnection *)connection;
- (YapDatabaseConnection *)registrationConnection;
@end
#pragma mark -
@interface OWSDatabase ()
@property (atomic, weak) id<OWSDatabaseConnectionDelegate> delegate;
@end
#pragma mark -
@implementation OWSDatabase
- (id)initWithPath:(NSString *)inPath
serializer:(nullable YapDatabaseSerializer)inSerializer
deserializer:(YapDatabaseDeserializer)inDeserializer
options:(YapDatabaseOptions *)inOptions
delegate:(id<OWSDatabaseConnectionDelegate>)delegate
{
self = [super initWithPath:inPath serializer:inSerializer deserializer:inDeserializer options:inOptions];
if (!self) {
return self;
}
self.delegate = delegate;
return self;
}
// This clobbers the superclass implementation to include asserts which
// ensure that the database is in a ready state before creating write transactions.
//
// See comments in OWSDatabaseConnection.
- (YapDatabaseConnection *)newConnection
{
id<OWSDatabaseConnectionDelegate> delegate = self.delegate;
OWSDatabaseConnection *connection = [[OWSDatabaseConnection alloc] initWithDatabase:self delegate:delegate];
[self addConnection:connection];
return connection;
}
- (YapDatabaseConnection *)registrationConnection
{
YapDatabaseConnection *connection = [super registrationConnection];
return connection;
}
@end
#pragma mark -
@interface OWSUnknownDBObject : TSYapDatabaseObject <NSCoding>
@end
#pragma mark -
/**
* A default object to return when we can't deserialize an object from YapDB. This can prevent crashes when
* old objects linger after their definition file is removed. The danger is that, the objects can lay in wait
* until the next time a DB extension is added and we necessarily enumerate the entire DB.
*/
@implementation OWSUnknownDBObject
- (void)encodeWithCoder:(NSCoder *)aCoder
{
return [super encodeWithCoder:aCoder];
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (!self) {
return self;
}
return self;
}
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
// No-op.
}
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
// No-op.
}
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
// No-op.
}
@end
#pragma mark -
@interface OWSUnarchiverDelegate : NSObject <NSKeyedUnarchiverDelegate>
@end
#pragma mark -
@implementation OWSUnarchiverDelegate
- (nullable Class)unarchiver:(NSKeyedUnarchiver *)unarchiver
cannotDecodeObjectOfClassName:(NSString *)name
originalClasses:(NSArray<NSString *> *)classNames
{
return [OWSUnknownDBObject class];
}
@end
#pragma mark -
@interface OWSStorage () <OWSDatabaseConnectionDelegate>
@property (atomic, nullable) YapDatabase *database;
@property (nonatomic) NSMutableArray<NSString *> *extensionNames;
@end
#pragma mark -
@implementation OWSStorage
- (instancetype)initStorage
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(resetStorage)
name:OWSResetStorageNotification
object:nil];
self.extensionNames = [NSMutableArray new];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)loadDatabase
{
if (![self tryToLoadDatabase]) {
// Failing to load the database is catastrophic.
//
// The best we can try to do is to discard the current database
// and behave like a clean install.
// Try to reset app by deleting all databases.
//
// TODO: Possibly clean up all app files.
// [OWSStorage deleteDatabaseFiles];
if (![self tryToLoadDatabase]) {
// Sleep to give analytics events time to be delivered.
[NSThread sleepForTimeInterval:15.0f];
NSAssert(NO, @"Couldn't load database");
}
}
}
- (nullable id)dbNotificationObject
{
return self.database;
}
- (BOOL)areAsyncRegistrationsComplete
{
return NO;
}
- (BOOL)areSyncRegistrationsComplete
{
return NO;
}
- (BOOL)areAllRegistrationsComplete
{
return self.areSyncRegistrationsComplete && self.areAsyncRegistrationsComplete;
}
- (void)runSyncRegistrations
{
}
- (void)runAsyncRegistrationsWithCompletion:(void (^_Nonnull)(void))completion
{
}
+ (void)registerExtensionsWithMigrationBlock:(OWSStorageMigrationBlock)migrationBlock
{
__block OWSBackgroundTask *_Nullable backgroundTask =
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
[OWSPrimaryStorage.sharedManager runSyncRegistrations];
[OWSPrimaryStorage.sharedManager runAsyncRegistrationsWithCompletion:^{
[self postRegistrationCompleteNotification];
migrationBlock();
backgroundTask = nil;
}];
}
- (YapDatabaseConnection *)registrationConnection
{
return self.database.registrationConnection;
}
// Returns YES IFF all registrations are complete.
+ (void)postRegistrationCompleteNotification
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSNotificationCenter defaultCenter] postNotificationNameAsync:StorageIsReadyNotification
object:nil
userInfo:nil];
});
}
+ (BOOL)isStorageReady
{
return OWSPrimaryStorage.sharedManager.areAllRegistrationsComplete;
}
+ (YapDatabaseOptions *)defaultDatabaseOptions
{
YapDatabaseOptions *options = [[YapDatabaseOptions alloc] init];
options.corruptAction = YapDatabaseCorruptAction_Fail;
options.enableMultiProcessSupport = YES;
// We leave a portion of the header decrypted so that iOS will recognize the file
// as a SQLite database. Otherwise, because the database lives in a shared data container,
// and our usage of sqlite's write-ahead logging retains a lock on the database, the OS
// would kill the app/share extension as soon as it is backgrounded.
options.cipherUnencryptedHeaderLength = kSqliteHeaderLength;
// If we want to migrate to the new cipher defaults in SQLCipher4+ we'll need to do a one time
// migration. See the `PRAGMA cipher_migrate` documentation for details.
// https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate
options.legacyCipherCompatibilityVersion = 3;
return options;
}
- (BOOL)tryToLoadDatabase
{
__weak OWSStorage *weakSelf = self;
YapDatabaseOptions *options = [self.class defaultDatabaseOptions];
options.cipherKeySpecBlock = ^{
// NOTE: It's critical that we don't capture a reference to self
// (e.g. by using OWSAssertDebug()) or this database will contain a
// circular reference and will leak.
OWSStorage *strongSelf = weakSelf;
// Rather than compute this once and capture the value of the key
// in the closure, we prefer to fetch the key from the keychain multiple times
// in order to keep the key out of application memory.
NSData *databaseKeySpec = [strongSelf databaseKeySpec];
return databaseKeySpec;
};
// Sanity checking elsewhere asserts we should only regenerate key specs when
// there is no existing database, so rather than lazily generate in the cipherKeySpecBlock
// we must ensure the keyspec exists before we create the database.
[self ensureDatabaseKeySpecExists];
OWSDatabase *database = [[OWSDatabase alloc] initWithPath:[self databaseFilePath]
serializer:nil
deserializer:[[self class] logOnFailureDeserializer]
options:options
delegate:self];
if (!database) {
return NO;
}
_database = database;
return YES;
}
/**
* NSCoding sometimes throws exceptions killing our app. We want to log that exception.
**/
+ (YapDatabaseDeserializer)logOnFailureDeserializer
{
OWSUnarchiverDelegate *unarchiverDelegate = [OWSUnarchiverDelegate new];
return ^id(NSString __unused *collection, NSString __unused *key, NSData *data) {
if (!data || data.length <= 0) {
return [OWSUnknownDBObject new];
}
@try {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
unarchiver.delegate = unarchiverDelegate;
return [unarchiver decodeObjectForKey:@"root"];
} @catch (NSException *exception) {
// Sync log in case we bail
@throw exception;
}
};
}
- (YapDatabaseConnection *)newDatabaseConnection
{
YapDatabaseConnection *dbConnection = self.database.newConnection;
return dbConnection;
}
#pragma mark - Extension Registration
+ (void)incrementVersionOfDatabaseExtension:(NSString *)extensionName
{
// Don't increment version of a given extension more than once
// per launch.
static NSMutableSet<NSString *> *incrementedViewSet = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
incrementedViewSet = [NSMutableSet new];
});
@synchronized(incrementedViewSet) {
if ([incrementedViewSet containsObject:extensionName]) {
return;
}
[incrementedViewSet addObject:extensionName];
}
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
NSMutableDictionary<NSString *, NSNumber *> *_Nullable versionMap =
[[appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap] mutableCopy];
if (!versionMap) {
versionMap = [NSMutableDictionary new];
}
NSNumber *_Nullable versionSuffix = versionMap[extensionName];
versionMap[extensionName] = @(versionSuffix.intValue + 1);
[appUserDefaults setValue:versionMap forKey:kNSUserDefaults_DatabaseExtensionVersionMap];
[appUserDefaults synchronize];
}
- (nullable NSString *)appendSuffixToDatabaseExtensionVersionIfNecessary:(nullable NSString *)versionTag
extensionName:(NSString *)extensionName
{
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
NSDictionary<NSString *, NSNumber *> *_Nullable versionMap =
[appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionMap];
NSNumber *_Nullable versionSuffix = versionMap[extensionName];
if (versionSuffix) {
NSString *result =
[NSString stringWithFormat:@"%@.%@", (versionTag.length < 1 ? @"0" : versionTag), versionSuffix];
return result;
}
return versionTag;
}
- (YapDatabaseExtension *)updateExtensionVersion:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
{
if ([extension isKindOfClass:[YapDatabaseAutoView class]]) {
YapDatabaseAutoView *databaseView = (YapDatabaseAutoView *)extension;
YapDatabaseAutoView *databaseViewCopy = [[YapDatabaseAutoView alloc]
initWithGrouping:databaseView.grouping
sorting:databaseView.sorting
versionTag:[self appendSuffixToDatabaseExtensionVersionIfNecessary:databaseView.versionTag
extensionName:extensionName]
options:databaseView.options];
return databaseViewCopy;
} else if ([extension isKindOfClass:[YapDatabaseSecondaryIndex class]]) {
YapDatabaseSecondaryIndex *secondaryIndex = (YapDatabaseSecondaryIndex *)extension;
YapDatabaseSecondaryIndex *secondaryIndexCopy = [[YapDatabaseSecondaryIndex alloc]
initWithSetup:secondaryIndex->setup
handler:secondaryIndex->handler
versionTag:[self appendSuffixToDatabaseExtensionVersionIfNecessary:secondaryIndex.versionTag
extensionName:extensionName]
options:secondaryIndex->options];
return secondaryIndexCopy;
} else if ([extension isKindOfClass:[YapDatabaseFullTextSearch class]]) {
YapDatabaseFullTextSearch *fullTextSearch = (YapDatabaseFullTextSearch *)extension;
NSString *versionTag = [self appendSuffixToDatabaseExtensionVersionIfNecessary:fullTextSearch.versionTag extensionName:extensionName];
YapDatabaseFullTextSearch *fullTextSearchCopy =
[[YapDatabaseFullTextSearch alloc] initWithColumnNames:fullTextSearch->columnNames.array
options:fullTextSearch->options
handler:fullTextSearch->handler
ftsVersion:fullTextSearch->ftsVersion
versionTag:versionTag];
return fullTextSearchCopy;
} else if ([extension isKindOfClass:[YapDatabaseCrossProcessNotification class]]) {
// versionTag doesn't matter for YapDatabaseCrossProcessNotification.
return extension;
} else {
// This method needs to be able to update the versionTag of all extensions.
// If we start using other extension types, we need to modify this method to
// handle them as well.
return extension;
}
}
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
{
extension = [self updateExtensionVersion:extension withName:extensionName];
[self.extensionNames addObject:extensionName];
return [self.database registerExtension:extension withName:extensionName];
}
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
withName:(NSString *)extensionName
{
[self asyncRegisterExtension:extension withName:extensionName completion:nil];
}
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
withName:(NSString *)extensionName
completion:(nullable dispatch_block_t)completion
{
extension = [self updateExtensionVersion:extension withName:extensionName];
[self.extensionNames addObject:extensionName];
[self.database asyncRegisterExtension:extension
withName:extensionName
completionBlock:^(BOOL ready) {
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion();
}
});
}];
}
- (nullable id)registeredExtension:(NSString *)extensionName
{
return [self.database registeredExtension:extensionName];
}
- (NSArray<NSString *> *)registeredExtensionNames
{
return [self.extensionNames copy];
}
#pragma mark - Password
+ (void)deleteDatabaseFiles
{
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath]];
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath_SHM]];
[OWSFileSystem deleteFile:[OWSPrimaryStorage legacyDatabaseFilePath_WAL]];
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath]];
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath_SHM]];
[OWSFileSystem deleteFile:[OWSPrimaryStorage sharedDataDatabaseFilePath_WAL]];
}
- (void)closeStorageForTests
{
[self resetStorage];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)resetStorage
{
self.database = nil;
[OWSStorage deleteDatabaseFiles];
}
+ (void)resetAllStorage
{
[[NSNotificationCenter defaultCenter] postNotificationName:OWSResetStorageNotification object:nil];
// This might be redundant but in the spirit of thoroughness...
[self deleteDatabaseFiles];
[self deleteDBKeys];
if (CurrentAppContext().isMainApp) {
[TSAttachmentStream deleteAttachments];
}
// TODO: Delete Profiles on Disk?
}
#pragma mark - Password
- (NSString *)databaseFilePath
{
return @"";
}
- (NSString *)databaseFilePath_SHM
{
return @"";
}
- (NSString *)databaseFilePath_WAL
{
return @"";
}
#pragma mark - Keychain
+ (BOOL)isDatabasePasswordAccessible
{
NSError *error;
NSData *cipherKeySpec = [self tryToLoadDatabaseCipherKeySpec:&error];
if (cipherKeySpec && !error) {
return YES;
}
return NO;
}
+ (nullable NSData *)tryToLoadDatabaseLegacyPassphrase:(NSError **)errorHandle
{
return [self tryToLoadKeyChainValue:keychainDBLegacyPassphrase errorHandle:errorHandle];
}
+ (nullable NSData *)tryToLoadDatabaseCipherKeySpec:(NSError **)errorHandle
{
NSData *_Nullable data = [self tryToLoadKeyChainValue:keychainDBCipherKeySpec errorHandle:errorHandle];
return data;
}
+ (void)storeDatabaseCipherKeySpec:(NSData *)cipherKeySpecData
{
[self storeKeyChainValue:cipherKeySpecData keychainKey:keychainDBCipherKeySpec];
}
+ (void)removeLegacyPassphrase
{
NSError *_Nullable error;
BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService
key:keychainDBLegacyPassphrase
error:&error];
}
- (void)ensureDatabaseKeySpecExists
{
NSError *error;
NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
if (error || (keySpec.length != kSQLCipherKeySpecLength)) {
// Because we use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
// the keychain will be inaccessible after device restart until
// device is unlocked for the first time. If the app receives
// a push notification, we won't be able to access the keychain to
// process that notification, so we should just terminate by throwing
// an uncaught exception.
NSString *errorDescription = [NSString
stringWithFormat:@"CipherKeySpec inaccessible. New install or no unlock since device restart? Error: %@",
error];
if (CurrentAppContext().isMainApp) {
UIApplicationState applicationState = CurrentAppContext().reportedApplicationState;
errorDescription = [errorDescription
stringByAppendingFormat:@", ApplicationState: %@", NSStringForUIApplicationState(applicationState)];
}
if (CurrentAppContext().isMainApp) {
if (CurrentAppContext().isInBackground) {
// Rather than crash here, we should have already detected the situation earlier
// and exited gracefully (in the app delegate) using isDatabasePasswordAccessible.
// This is a last ditch effort to avoid blowing away the user's database.
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:errorDescription];
}
} else {
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible; not main app."];
}
// At this point, either this is a new install so there's no existing password to retrieve
// or the keychain has become corrupt. Either way, we want to get back to a
// "known good state" and behave like a new install.
BOOL doesDBExist = [NSFileManager.defaultManager fileExistsAtPath:[self databaseFilePath]];
if (!CurrentAppContext().isRunningTests) {
// Try to reset app by deleting database.
[OWSStorage resetAllStorage];
}
keySpec = [Randomness generateRandomBytes:(int)kSQLCipherKeySpecLength];
[[self class] storeDatabaseCipherKeySpec:keySpec];
}
}
- (NSData *)databaseKeySpec
{
NSError *error;
NSData *_Nullable keySpec = [[self class] tryToLoadDatabaseCipherKeySpec:&error];
if (error) {
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec inaccessible"];
}
if (keySpec.length != kSQLCipherKeySpecLength) {
[self raiseKeySpecInaccessibleExceptionWithErrorDescription:@"CipherKeySpec invalid"];
}
return keySpec;
}
- (void)raiseKeySpecInaccessibleExceptionWithErrorDescription:(NSString *)errorDescription
{
// Sleep to give analytics events time to be delivered.
[NSThread sleepForTimeInterval:5.0f];
// Presumably this happened in response to a push notification. It's possible that the keychain is corrupted
// but it could also just be that the user hasn't yet unlocked their device since our password is
// kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
}
+ (void)deleteDBKeys
{
NSError *_Nullable error;
BOOL result = [CurrentAppContext().keychainStorage removeWithService:keychainService
key:keychainDBLegacyPassphrase
error:&error];
result = [CurrentAppContext().keychainStorage removeWithService:keychainService
key:keychainDBCipherKeySpec
error:&error];
}
- (unsigned long long)databaseFileSize
{
return [OWSFileSystem fileSizeOfPath:self.databaseFilePath].unsignedLongLongValue;
}
- (unsigned long long)databaseWALFileSize
{
return [OWSFileSystem fileSizeOfPath:self.databaseFilePath_WAL].unsignedLongLongValue;
}
- (unsigned long long)databaseSHMFileSize
{
return [OWSFileSystem fileSizeOfPath:self.databaseFilePath_SHM].unsignedLongLongValue;
}
+ (nullable NSData *)tryToLoadKeyChainValue:(NSString *)keychainKey errorHandle:(NSError **)errorHandle
{
NSData *_Nullable data =
[CurrentAppContext().keychainStorage dataForService:keychainService key:keychainKey error:errorHandle];
return data;
}
+ (void)storeKeyChainValue:(NSData *)data keychainKey:(NSString *)keychainKey
{
NSError *error;
BOOL success =
[CurrentAppContext().keychainStorage setWithData:data service:keychainService key:keychainKey error:&error];
if (!success || error) {
// Sleep to give analytics events time to be delivered.
[NSThread sleepForTimeInterval:15.0f];
}
}
- (void)logFileSizes
{
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,209 +0,0 @@
extension Storage {
// MARK: - Open Groups
private static let openGroupCollection = "SNOpenGroupCollection"
@objc public func getAllV2OpenGroups() -> [String:OpenGroupV2] {
var result = [String:OpenGroupV2]()
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection) { threadID, object, _ in
guard let openGroup = object as? OpenGroupV2 else { return }
result[threadID] = openGroup
}
}
return result
}
@objc(getV2OpenGroupForThreadID:)
public func getV2OpenGroup(for threadID: String) -> OpenGroupV2? {
var result: OpenGroupV2?
Storage.read { transaction in
result = transaction.object(forKey: threadID, inCollection: Storage.openGroupCollection) as? OpenGroupV2
}
return result
}
public func v2GetThreadID(for v2OpenGroupID: String) -> String? {
var result: String?
Storage.read { transaction in
transaction.enumerateKeysAndObjects(inCollection: Storage.openGroupCollection, using: { threadID, object, stop in
guard let openGroup = object as? OpenGroupV2, openGroup.id == v2OpenGroupID else { return }
result = threadID
stop.pointee = true
})
}
return result
}
@objc(setV2OpenGroup:forThreadWithID:using:)
public func setV2OpenGroup(_ openGroup: OpenGroupV2, for threadID: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(openGroup, forKey: threadID, inCollection: Storage.openGroupCollection)
}
@objc(removeV2OpenGroupForThreadID:using:)
public func removeV2OpenGroup(for threadID: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: threadID, inCollection: Storage.openGroupCollection)
}
// MARK: - Authorization
private static let authTokenCollection = "SNAuthTokenCollection"
public func getAuthToken(for room: String, on server: String) -> String? {
let collection = Storage.authTokenCollection
let key = "\(server).\(room)"
var result: String? = nil
Storage.read { transaction in
result = transaction.object(forKey: key, inCollection: collection) as? String
}
return result
}
public func setAuthToken(for room: String, on server: String, to newValue: String, using transaction: Any) {
let collection = Storage.authTokenCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
}
public func removeAuthToken(for room: String, on server: String, using transaction: Any) {
let collection = Storage.authTokenCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
}
// MARK: - Public Keys
private static let openGroupPublicKeyCollection = "LokiOpenGroupPublicKeyCollection"
public func getOpenGroupPublicKey(for server: String) -> String? {
var result: String? = nil
Storage.read { transaction in
result = transaction.object(forKey: server, inCollection: Storage.openGroupPublicKeyCollection) as? String
}
return result
}
public func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: server, inCollection: Storage.openGroupPublicKeyCollection)
}
public func removeOpenGroupPublicKey(for server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: server, inCollection: Storage.openGroupPublicKeyCollection)
}
// MARK: - Last Message Server ID
public static let lastMessageServerIDCollection = "SNLastMessageServerIDCollection"
public func getLastMessageServerID(for room: String, on server: String) -> Int64? {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
var result: Int64? = nil
Storage.read { transaction in
result = transaction.object(forKey: key, inCollection: collection) as? Int64
}
return result
}
public func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
}
public func removeLastMessageServerID(for room: String, on server: String, using transaction: Any) {
let collection = Storage.lastMessageServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
}
// MARK: - Last Deletion Server ID
public static let lastDeletionServerIDCollection = "SNLastDeletionServerIDCollection"
public func getLastDeletionServerID(for room: String, on server: String) -> Int64? {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
var result: Int64? = nil
Storage.read { transaction in
result = transaction.object(forKey: key, inCollection: collection) as? Int64
}
return result
}
public func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any) {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: key, inCollection: collection)
}
public func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any) {
let collection = Storage.lastDeletionServerIDCollection
let key = "\(server).\(room)"
(transaction as! YapDatabaseReadWriteTransaction).removeObject(forKey: key, inCollection: collection)
}
// MARK: - OpenGroupServerIdToUniqueIdLookup
public static let openGroupServerIdToUniqueIdLookupCollection = "SNOpenGroupServerIdToUniqueIdLookup"
public func getOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadTransaction) -> OpenGroupServerIdLookup? {
let key: String = OpenGroupServerIdLookup.id(serverId: serverId, in: room, on: server)
return transaction.object(forKey: key, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection) as? OpenGroupServerIdLookup
}
public func addOpenGroupServerIdLookup(_ serverId: UInt64?, tsMessageId: String?, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction) {
guard let serverId: UInt64 = serverId, let tsMessageId: String = tsMessageId else { return }
let lookup: OpenGroupServerIdLookup = OpenGroupServerIdLookup(server: server, room: room, serverId: serverId, tsMessageId: tsMessageId)
addOpenGroupServerIdLookup(lookup, using: transaction)
}
public func addOpenGroupServerIdLookup(_ lookup: OpenGroupServerIdLookup, using transaction: YapDatabaseReadWriteTransaction) {
transaction.setObject(lookup, forKey: lookup.id, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection)
}
public func removeOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction) {
let key: String = OpenGroupServerIdLookup.id(serverId: serverId, in: room, on: server)
transaction.removeObject(forKey: key, inCollection: Storage.openGroupServerIdToUniqueIdLookupCollection)
}
// MARK: - Metadata
private static let openGroupUserCountCollection = "SNOpenGroupUserCountCollection"
private static let openGroupImageCollection = "SNOpenGroupImageCollection"
public func getUserCount(forV2OpenGroupWithID openGroupID: String) -> UInt64? {
var result: UInt64?
Storage.read { transaction in
result = transaction.object(forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection) as? UInt64
}
return result
}
public func setUserCount(to newValue: UInt64, forV2OpenGroupWithID openGroupID: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(newValue, forKey: openGroupID, inCollection: Storage.openGroupUserCountCollection)
}
public func getOpenGroupImage(for room: String, on server: String) -> Data? {
var result: Data?
Storage.read { transaction in
result = transaction.object(forKey: "\(server).\(room)", inCollection: Storage.openGroupImageCollection) as? Data
}
return result
}
public func setOpenGroupImage(to data: Data, for room: String, on server: String, using transaction: Any) {
(transaction as! YapDatabaseReadWriteTransaction).setObject(data, forKey: "\(server).\(room)", inCollection: Storage.openGroupImageCollection)
}
}

View File

@ -1,40 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import PromiseKit
import Sodium
extension Storage {
@discardableResult
public func write(with block: @escaping (Any) -> Void) -> Promise<Void> {
Storage.write(with: { block($0) })
}
@discardableResult
public func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise<Void> {
Storage.write(with: { block($0) }, completion: completion)
}
public func writeSync(with block: @escaping (Any) -> Void) {
Storage.writeSync { block($0) }
}
// @objc public func getUser() -> Legacy.Contact? {
// return getUser(using: nil)
// }
//
// public func getUser(using transaction: YapDatabaseReadTransaction?) -> Legacy.Contact? {
// let userPublicKey = getUserHexEncodedPublicKey()
// var result: Legacy.Contact?
//
// if let transaction = transaction {
// result = Storage.shared.getContact(with: userPublicKey, using: transaction)
// }
// else {
// Storage.read { transaction in
// result = Storage.shared.getContact(with: userPublicKey, using: transaction)
// }
// }
// return result
// }
}

View File

@ -1,22 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
#import <YapDatabase/YapDatabaseTransaction.h>
NS_ASSUME_NONNULL_BEGIN
@interface TSDatabaseSecondaryIndexes : NSObject
+ (NSString *)registerTimeStampIndexExtensionName;
+ (YapDatabaseSecondaryIndex *)registerTimeStampIndex;
+ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp
withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block
usingTransaction:(YapDatabaseReadTransaction *)transaction;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,53 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "TSDatabaseSecondaryIndexes.h"
#import "OWSStorage.h"
NS_ASSUME_NONNULL_BEGIN
#define TSTimeStampSQLiteIndex @"messagesTimeStamp"
@implementation TSDatabaseSecondaryIndexes
+ (NSString *)registerTimeStampIndexExtensionName
{
return @"idx";
}
+ (YapDatabaseSecondaryIndex *)registerTimeStampIndex {
YapDatabaseSecondaryIndexSetup *setup = [[YapDatabaseSecondaryIndexSetup alloc] init];
[setup addColumn:TSTimeStampSQLiteIndex withType:YapDatabaseSecondaryIndexTypeReal];
YapDatabaseSecondaryIndexWithObjectBlock block =
^(YapDatabaseReadTransaction *transaction, NSMutableDictionary *dict, NSString *collection, NSString *key, id object) {
if ([object isKindOfClass:[TSInteraction class]]) {
TSInteraction *interaction = (TSInteraction *)object;
[dict setObject:@(interaction.timestamp) forKey:TSTimeStampSQLiteIndex];
}
};
YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block];
YapDatabaseSecondaryIndex *secondaryIndex =
[[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler versionTag:nil];
return secondaryIndex;
}
+ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp
withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block
usingTransaction:(YapDatabaseReadTransaction *)transaction
{
NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = %lld", TSTimeStampSQLiteIndex, timestamp];
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString];
[[transaction ext:[self registerTimeStampIndexExtensionName]] enumerateKeysMatchingQuery:query usingBlock:block];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,69 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <SessionMessagingKit/OWSStorage.h>
#import <YapDatabase/YapDatabaseViewTransaction.h>
NS_ASSUME_NONNULL_BEGIN
extern NSString *const TSInboxGroup;
extern NSString *const TSMessageRequestGroup;
extern NSString *const TSArchiveGroup;
extern NSString *const TSShareExtensionGroup;
extern NSString *const TSUnreadIncomingMessagesGroup;
extern NSString *const TSSecondaryDevicesGroup;
extern NSString *const TSThreadDatabaseViewExtensionName;
extern NSString *const TSThreadShareExtensionDatabaseViewExtensionName;
extern NSString *const TSMessageDatabaseViewExtensionName;
extern NSString *const TSMessageDatabaseViewExtensionName_Legacy;
extern NSString *const TSUnreadDatabaseViewExtensionName;
extern NSString *const TSUnseenDatabaseViewExtensionName;
extern NSString *const TSUnreadMentionDatabaseViewExtensionName;
extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName;
extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName;
extern NSString *const TSSecondaryDevicesDatabaseViewExtensionName;
extern NSString *const TSLazyRestoreAttachmentsGroup;
extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName;
@interface TSDatabaseView : NSObject
- (instancetype)init NS_UNAVAILABLE;
#pragma mark - Views
// Returns the "unseen" database view if it is ready;
// otherwise it returns the "unread" database view.
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction;
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction;
+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction;
#pragma mark - Registration
+ (void)registerCrossProcessNotifier:(OWSStorage *)storage;
// This method must be called _AFTER_ asyncRegisterThreadInteractionsDatabaseView.
+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage;
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage;
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage;
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage;
// Should be used for "mention indicator".
//
// Instances of OWSReadTracking for wasRead is NO and isUserMentioned is YES.
+ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage;
+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,441 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "TSDatabaseView.h"
#import <YapDatabase/YapDatabaseAutoView.h>
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
#import <YapDatabase/YapDatabaseViewTypes.h>
#import <SessionUtilitiesKit/AppContext.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const TSInboxGroup = @"TSInboxGroup";
NSString *const TSMessageRequestGroup = @"TSMessageRequestGroup";
NSString *const TSArchiveGroup = @"TSArchiveGroup";
NSString *const TSShareExtensionGroup = @"TSShareExtensionGroup";
NSString *const TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
NSString *const TSSecondaryDevicesGroup = @"TSSecondaryDevicesGroup";
// YAPDB BUG: when changing from non-persistent to persistent view, we had to rename TSThreadDatabaseViewExtensionName
// -> TSThreadDatabaseViewExtensionName2 to work around https://github.com/yapstudios/YapDatabase/issues/324
NSString *const TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName2";
NSString *const TSThreadShareExtensionDatabaseViewExtensionName = @"TSThreadShareExtensionDatabaseViewExtensionName";
// We sort interactions by a monotonically increasing counter.
//
// Previously we sorted the interactions database by local timestamp, which was problematic if the local clock changed.
// We need to maintain the legacy extension for purposes of migration.
//
// The "Legacy" sorting extension name constant has the same value as always, so that it won't need to be rebuilt, while
// the "Modern" sorting extension name constant has the same symbol name that we've always used for sorting
// interactions, so that the callsites won't need to change.
NSString *const TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName_Monotonic";
NSString *const TSMessageDatabaseViewExtensionName_Legacy = @"TSMessageDatabaseViewExtensionName";
NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName = @"TSThreadOutgoingMessageDatabaseViewExtensionName";
NSString *const TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
NSString *const TSUnseenDatabaseViewExtensionName = @"TSUnseenDatabaseViewExtensionName";
NSString *const TSUnreadMentionDatabaseViewExtensionName = @"TSUnreadMentionDatabaseViewExtensionName";
NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName = @"TSThreadSpecialMessagesDatabaseViewExtensionName";
NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevicesDatabaseViewExtensionName";
NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName
= @"TSLazyRestoreAttachmentsDatabaseViewExtensionName";
NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup";
@interface OWSStorage (TSDatabaseView)
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
@end
#pragma mark -
@implementation TSDatabaseView
+ (void)registerCrossProcessNotifier:(OWSStorage *)storage
{
// I don't think the identifier and name of this extension matter for our purposes,
// so long as they don't conflict with any other extension names.
YapDatabaseExtension *extension =
[[YapDatabaseCrossProcessNotification alloc] initWithIdentifier:@"SignalCrossProcessNotifier"];
[storage registerExtension:extension withName:@"SignalCrossProcessNotifier"];
}
+ (void)registerMessageDatabaseViewWithName:(NSString *)viewName
viewGrouping:(YapDatabaseViewGrouping *)viewGrouping
version:(NSString *)version
storage:(OWSStorage *)storage
{
YapDatabaseView *existingView = [storage registeredExtension:viewName];
if (existingView) {
return;
}
YapDatabaseViewSorting *viewSorting = [self messagesSorting];
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
options.isPersistent = YES;
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
YapDatabaseView *view = [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping
sorting:viewSorting
versionTag:version
options:options];
[storage asyncRegisterExtension:view withName:viewName];
}
+ (void)asyncRegisterUnreadMentionDatabaseView:(OWSStorage *)storage
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if ([object isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *message = (TSIncomingMessage *)object;
if (!message.wasRead && message.isUserMentioned) {
return message.uniqueThreadId;
}
}
return nil;
}];
[self registerMessageDatabaseViewWithName:TSUnreadMentionDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"
storage:storage];
}
+ (void)asyncRegisterLegacyThreadInteractionsDatabaseView:(OWSStorage *)storage
{
YapDatabaseView *existingView = [storage registeredExtension:TSMessageDatabaseViewExtensionName_Legacy];
if (existingView) {
return;
}
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSInteraction class]]) {
return nil;
}
TSInteraction *interaction = (TSInteraction *)object;
return interaction.uniqueThreadId;
}];
YapDatabaseViewSorting *viewSorting =
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
NSString *group,
NSString *collection1,
NSString *key1,
id object1,
NSString *collection2,
NSString *key2,
id object2) {
if (![object1 isKindOfClass:[TSInteraction class]]) {
return NSOrderedSame;
}
if (![object2 isKindOfClass:[TSInteraction class]]) {
return NSOrderedSame;
}
TSInteraction *interaction1 = (TSInteraction *)object1;
TSInteraction *interaction2 = (TSInteraction *)object2;
// Legit usage of timestampForLegacySorting since we're registering the
// legacy extension
uint64_t timestamp1 = interaction1.timestampForLegacySorting;
uint64_t timestamp2 = interaction2.timestampForLegacySorting;
if (timestamp1 > timestamp2) {
return NSOrderedDescending;
} else if (timestamp1 < timestamp2) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
}];
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
options.isPersistent = YES;
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
YapDatabaseView *view =
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"1" options:options];
[storage asyncRegisterExtension:view withName:TSMessageDatabaseViewExtensionName_Legacy];
}
+ (void)asyncRegisterThreadInteractionsDatabaseView:(OWSStorage *)storage
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSInteraction class]]) {
return nil;
}
TSInteraction *interaction = (TSInteraction *)object;
return interaction.uniqueThreadId;
}];
[self registerMessageDatabaseViewWithName:TSMessageDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"
storage:storage];
}
+ (void)asyncRegisterThreadOutgoingMessagesDatabaseView:(OWSStorage *)storage
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if ([object isKindOfClass:[TSOutgoingMessage class]]) {
return ((TSOutgoingMessage *)object).uniqueThreadId;
}
return nil;
}];
[self registerMessageDatabaseViewWithName:TSThreadOutgoingMessageDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"3"
storage:storage];
}
+ (void)asyncRegisterThreadDatabaseView:(OWSStorage *)storage
{
YapDatabaseView *threadView = [storage registeredExtension:TSThreadDatabaseViewExtensionName];
if (threadView) {
return;
}
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSThread class]]) {
return nil;
}
TSThread *thread = (TSThread *)object;
if ([thread isMessageRequestUsingTransaction:transaction]) {
// Don't show blocked threads at all
if (thread.isBlocked) {
return nil;
}
return TSMessageRequestGroup;
}
else if (thread.shouldBeVisible) {
// Do nothing; we never hide threads that have ever had a message.
} else {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId];
if (threadMessageCount < 1) {
return nil;
}
}
return TSInboxGroup;
}];
YapDatabaseViewSorting *viewSorting = [self threadSorting];
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
options.isPersistent = YES;
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
YapDatabaseView *databaseView =
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options];
[storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
YapDatabaseView *shareExtensionThreadView = [storage registeredExtension:TSThreadShareExtensionDatabaseViewExtensionName];
if (shareExtensionThreadView) {
return;
}
YapDatabaseViewGrouping *shareExtensionViewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSThread class]]) {
return nil;
}
TSThread *thread = (TSThread *)object;
if ([thread isMessageRequestUsingTransaction:transaction]) {
return nil;
}
else {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId];
if (threadMessageCount < 1) {
return nil;
}
if (!thread.isGroupThread) {
TSContactThread *contactThead = (TSContactThread *)thread;
SMKContact *contact = [SMKContact fetchOrCreateWithId:[contactThead contactSessionID]];
if (contact == nil || !contact.didApproveMe) {
return nil;
}
}
}
return TSShareExtensionGroup;
}];
YapDatabaseViewSorting *shareExtensionViewSorting = [self threadSorting];
YapDatabaseViewOptions *shareExtensionOptions = [[YapDatabaseViewOptions alloc] init];
shareExtensionOptions.isPersistent = YES;
shareExtensionOptions.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
YapDatabaseView *shareExtensionDatabaseView =
[[YapDatabaseAutoView alloc] initWithGrouping:shareExtensionViewGrouping sorting:shareExtensionViewSorting versionTag:@"1" options:shareExtensionOptions];
[storage asyncRegisterExtension:shareExtensionDatabaseView withName:TSThreadShareExtensionDatabaseViewExtensionName];
}
+ (YapDatabaseViewSorting *)threadSorting {
return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
NSString *group,
NSString *collection1,
NSString *key1,
id object1,
NSString *collection2,
NSString *key2,
id object2) {
if (![object1 isKindOfClass:[TSThread class]]) {
return NSOrderedSame;
}
if (![object2 isKindOfClass:[TSThread class]]) {
return NSOrderedSame;
}
TSThread *thread1 = (TSThread *)object1;
TSThread *thread2 = (TSThread *)object2;
if ([group isEqualToString:TSArchiveGroup] || [group isEqualToString:TSInboxGroup]) {
if (thread1.isPinned != thread2.isPinned) {
if (thread1.isPinned) { return NSOrderedDescending; }
if (thread2.isPinned) { return NSOrderedAscending; }
}
TSInteraction *_Nullable lastInteractionForInbox1 =
[thread1 lastInteractionForInboxWithTransaction:transaction];
NSDate *lastInteractionForInboxDate1 = lastInteractionForInbox1 ? lastInteractionForInbox1.receivedAtDate : thread1.creationDate;
TSInteraction *_Nullable lastInteractionForInbox2 =
[thread2 lastInteractionForInboxWithTransaction:transaction];
NSDate *lastInteractionForInboxDate2 = lastInteractionForInbox2 ? lastInteractionForInbox2.receivedAtDate : thread2.creationDate;
NSDate *date1 = thread1.lastInteractionDate ?: lastInteractionForInboxDate1 ?: thread1.creationDate;
NSDate *date2 = thread2.lastInteractionDate ?: lastInteractionForInboxDate2 ?: thread2.creationDate;
return [date1 compare:date2];
}
return NSOrderedSame;
}];
}
+ (YapDatabaseViewSorting *)messagesSorting {
return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
NSString *group,
NSString *collection1,
NSString *key1,
id object1,
NSString *collection2,
NSString *key2,
id object2) {
if (![object1 isKindOfClass:[TSInteraction class]]) {
return NSOrderedSame;
}
if (![object2 isKindOfClass:[TSInteraction class]]) {
return NSOrderedSame;
}
TSInteraction *message1 = (TSInteraction *)object1;
TSInteraction *message2 = (TSInteraction *)object2;
return [message1 compareForSorting:message2];
}];
}
+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage
{
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable(
YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) {
if (![object isKindOfClass:[TSAttachment class]]) {
return nil;
}
if (![object isKindOfClass:[TSAttachmentPointer class]]) {
return nil;
}
TSAttachmentPointer *attachmentPointer = (TSAttachmentPointer *)object;
if (attachmentPointer.lazyRestoreFragment) {
return TSLazyRestoreAttachmentsGroup;
} else {
return nil;
}
}];
YapDatabaseViewSorting *viewSorting =
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
NSString *group,
NSString *collection1,
NSString *key1,
id object1,
NSString *collection2,
NSString *key2,
id object2) {
if (![object1 isKindOfClass:[TSAttachmentPointer class]]) {
return NSOrderedSame;
}
if (![object2 isKindOfClass:[TSAttachmentPointer class]]) {
return NSOrderedSame;
}
// Specific ordering doesn't matter; we just need a stable ordering.
TSAttachmentPointer *attachmentPointer1 = (TSAttachmentPointer *)object1;
TSAttachmentPointer *attachmentPointer2 = (TSAttachmentPointer *)object2;
return [attachmentPointer1.uniqueId compare:attachmentPointer2.uniqueId];
}];
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
options.isPersistent = YES;
options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]];
YapDatabaseView *view =
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"4" options:options];
[storage asyncRegisterExtension:view withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName];
}
+ (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction
{
id _Nullable result = [transaction ext:TSUnseenDatabaseViewExtensionName];
// TODO: I believe we can now safely remove this?
if (!result) {
result = [transaction ext:TSUnreadDatabaseViewExtensionName];
}
return result;
}
// MJK TODO - dynamic interactions
+ (id)threadOutgoingMessageDatabaseView:(YapDatabaseReadTransaction *)transaction
{
id result = [transaction ext:TSThreadOutgoingMessageDatabaseViewExtensionName];
return result;
}
+ (id)threadSpecialMessagesDatabaseView:(YapDatabaseReadTransaction *)transaction
{
id result = [transaction ext:TSThreadSpecialMessagesDatabaseViewExtensionName];
return result;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,5 +1,9 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import PromiseKit
import SessionSnodeKit
import SessionUtilitiesKit
@objc(SNFileServerAPIV2)
public final class FileServerAPIV2 : NSObject {

View File

@ -7,13 +7,5 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
#import <SessionMessagingKit/NSData+messagePadding.h>
#import <SessionMessagingKit/OWSAudioPlayer.h>
#import <SessionMessagingKit/OWSBackgroundTask.h>
#import <SessionMessagingKit/OWSBackupFragment.h>
#import <SessionMessagingKit/OWSPreferences.h>
#import <SessionMessagingKit/OWSPrimaryStorage.h>
#import <SessionMessagingKit/OWSStorage.h>
#import <SessionMessagingKit/OWSStorage+Subclass.h>
#import <SessionMessagingKit/OWSWindowManager.h>
#import <SessionMessagingKit/TSDatabaseSecondaryIndexes.h>
#import <SessionMessagingKit/TSDatabaseView.h>
#import <SessionMessagingKit/YapDatabaseConnection+OWS.h>
#import <SessionMessagingKit/YapDatabaseTransaction+OWS.h>

View File

@ -6,6 +6,7 @@ import Sodium
import Curve25519Kit
import SignalCoreKit
import SessionSnodeKit
import SessionUtilitiesKit
extension MessageReceiver {

View File

@ -3,6 +3,7 @@
import GRDB
import PromiseKit
import SessionSnodeKit
import SessionUtilitiesKit
@objc(LKPushNotificationAPI)
public final class PushNotificationAPI : NSObject {

View File

@ -4,6 +4,7 @@ import Foundation
import GRDB
import PromiseKit
import SessionSnodeKit
import SessionUtilitiesKit
@objc(LKClosedGroupPoller)
public final class ClosedGroupPoller: NSObject {

View File

@ -5,6 +5,7 @@ import GRDB
import PromiseKit
import Sodium
import SessionSnodeKit
import SessionUtilitiesKit
public final class Poller {
private var isPolling: Atomic<Bool> = Atomic(false)

View File

@ -3,6 +3,7 @@
import Foundation
import GRDB
import DifferenceKit
import SessionUtilitiesKit
fileprivate typealias ViewModel = SessionThreadViewModel

View File

@ -1,56 +0,0 @@
import PromiseKit
import Sodium
import SessionSnodeKit
public protocol SessionMessagingKitStorageProtocol {
// MARK: - Shared
@discardableResult
func write(with block: @escaping (Any) -> Void) -> Promise<Void>
@discardableResult
func write(with block: @escaping (Any) -> Void, completion: @escaping () -> Void) -> Promise<Void>
func writeSync(with block: @escaping (Any) -> Void)
// MARK: - Authorization
func getAuthToken(for room: String, on server: String) -> String?
func setAuthToken(for room: String, on server: String, to newValue: String, using transaction: Any)
func removeAuthToken(for room: String, on server: String, using transaction: Any)
// MARK: - Open Groups
func getAllV2OpenGroups() -> [String:OpenGroupV2]
func getV2OpenGroup(for threadID: String) -> OpenGroupV2?
func v2GetThreadID(for v2OpenGroupID: String) -> String?
// MARK: - Open Group Public Keys
func getOpenGroupPublicKey(for server: String) -> String?
func setOpenGroupPublicKey(for server: String, to newValue: String, using transaction: Any)
// MARK: - Last Message Server ID
func getLastMessageServerID(for room: String, on server: String) -> Int64?
func setLastMessageServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
func removeLastMessageServerID(for room: String, on server: String, using transaction: Any)
// MARK: - Last Deletion Server ID
func getLastDeletionServerID(for room: String, on server: String) -> Int64?
func setLastDeletionServerID(for room: String, on server: String, to newValue: Int64, using transaction: Any)
func removeLastDeletionServerID(for room: String, on server: String, using transaction: Any)
// MARK: - OpenGroupServerIdToUniqueIdLookup
func getOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadTransaction) -> OpenGroupServerIdLookup?
func addOpenGroupServerIdLookup(_ serverId: UInt64?, tsMessageId: String?, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction)
func addOpenGroupServerIdLookup(_ lookup: OpenGroupServerIdLookup, using transaction: YapDatabaseReadWriteTransaction)
func removeOpenGroupServerIdLookup(_ serverId: UInt64, in room: String, on server: String, using transaction: YapDatabaseReadWriteTransaction)
// MARK: - Open Group Metadata
func setUserCount(to newValue: UInt64, forV2OpenGroupWithID openGroupID: String, using transaction: Any)
}
extension Storage: SessionMessagingKitStorageProtocol {}

View File

@ -6,11 +6,9 @@ import SessionUtilitiesKit
public class Environment {
public static var shared: Environment!
public let primaryStorage: OWSPrimaryStorage
public let reachabilityManager: SSKReachabilityManager
public let audioSession: OWSAudioSession
public let preferences: OWSPreferences
public let proximityMonitoringManager: OWSProximityMonitoringManager
public let windowManager: OWSWindowManager
public var isRequestingPermission: Bool
@ -22,34 +20,20 @@ public class Environment {
(notificationsManager.wrappedValue != nil)
}
public var objectReadWriteConnection: YapDatabaseConnection
public var sessionStoreDBConnection: YapDatabaseConnection
public var migrationDBConnection: YapDatabaseConnection
public var analyticsDBConnection: YapDatabaseConnection
// MARK: - Initialization
public init(
primaryStorage: OWSPrimaryStorage,
reachabilityManager: SSKReachabilityManager,
audioSession: OWSAudioSession,
preferences: OWSPreferences,
proximityMonitoringManager: OWSProximityMonitoringManager,
windowManager: OWSWindowManager
) {
self.primaryStorage = primaryStorage
self.reachabilityManager = reachabilityManager
self.audioSession = audioSession
self.preferences = preferences
self.proximityMonitoringManager = proximityMonitoringManager
self.windowManager = windowManager
self.isRequestingPermission = false
self.objectReadWriteConnection = primaryStorage.newDatabaseConnection()
self.sessionStoreDBConnection = primaryStorage.newDatabaseConnection()
self.migrationDBConnection = primaryStorage.newDatabaseConnection()
self.analyticsDBConnection = primaryStorage.newDatabaseConnection()
if Environment.shared == nil {
Environment.shared = self
}
@ -68,7 +52,6 @@ public class Environment {
class SMKEnvironment: NSObject {
@objc public static let shared: SMKEnvironment = SMKEnvironment()
@objc public var primaryStorage: OWSPrimaryStorage { Environment.shared.primaryStorage }
@objc public var audioSession: OWSAudioSession { Environment.shared.audioSession }
@objc public var windowManager: OWSWindowManager { Environment.shared.windowManager }

View File

@ -3,6 +3,7 @@
import Foundation
import AVFoundation
import SignalCoreKit
import SessionUtilitiesKit
@objc(OWSAudioActivity)
public class AudioActivity: NSObject {

View File

@ -2,6 +2,7 @@
import Foundation
import SignalCoreKit
import SessionUtilitiesKit
@objc
public protocol OWSProximityMonitoringManager: AnyObject {

View File

@ -2,6 +2,7 @@
import Foundation
import SessionSnodeKit
import SessionUtilitiesKit
public extension SNProtoEnvelope {
static func from(_ message: SnodeReceivedMessage) -> SNProtoEnvelope? {

View File

@ -1,43 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <YapDatabase/YapDatabaseConnection.h>
@class ECKeyPair;
@class PreKeyRecord;
@class SignedPreKeyRecord;
@class PreKeyBundle;
NS_ASSUME_NONNULL_BEGIN
@interface YapDatabaseConnection (OWS)
- (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection;
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue;
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue;
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection;
- (NSUInteger)numberOfKeysInCollection:(NSString *)collection;
#pragma mark -
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection;
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection;
- (void)setDouble:(double)value forKey:(NSString *)key inCollection:(NSString *)collection;
- (void)removeObjectForKey:(NSString *)string inCollection:(NSString *)collection;
- (void)setInt:(int)integer forKey:(NSString *)key inCollection:(NSString *)collection;
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection;
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection;
- (void)purgeCollection:(NSString *)collection;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,154 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "YapDatabaseConnection+OWS.h"
#import <Curve25519Kit/Curve25519.h>
#import <YapDatabase/YapDatabaseTransaction.h>
NS_ASSUME_NONNULL_BEGIN
@implementation YapDatabaseConnection (OWS)
- (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection
{
return nil != [self objectForKey:key inCollection:collection];
}
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection
{
__block NSString *_Nullable object;
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
object = [transaction objectForKey:key inCollection:collection];
}];
return object;
}
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class)class
{
id _Nullable value = [self objectForKey:key inCollection:collection];
return value;
}
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]];
}
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSString class]];
}
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return value ? [value boolValue] : defaultValue;
}
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return value ? [value doubleValue] : defaultValue;
}
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSData class]];
}
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[ECKeyPair class]];
}
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable number = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return [number intValue];
}
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
if (value) {
return [NSDate dateWithTimeIntervalSince1970:value.doubleValue];
} else {
return nil;
}
}
#pragma mark -
- (NSUInteger)numberOfKeysInCollection:(NSString *)collection
{
__block NSUInteger result;
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
result = [transaction numberOfKeysInCollection:collection];
}];
return result;
}
- (void)purgeCollection:(NSString *)collection
{
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeAllObjectsInCollection:collection];
}];
}
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection
{
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction setObject:object forKey:key inCollection:collection];
}];
}
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
if (oldValue && [@(value) isEqual:oldValue]) {
// Skip redundant writes.
return;
}
[self setObject:@(value) forKey:key inCollection:collection];
}
- (void)setDouble:(double)value forKey:(NSString *)key inCollection:(NSString *)collection
{
[self setObject:@(value) forKey:key inCollection:collection];
}
- (void)removeObjectForKey:(NSString *)key inCollection:(NSString *)collection
{
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeObjectForKey:key inCollection:collection];
}];
}
- (void)setInt:(int)value forKey:(NSString *)key inCollection:(NSString *)collection
{
[self setObject:@(value) forKey:key inCollection:collection];
}
- (int)incrementIntForKey:(NSString *)key inCollection:(NSString *)collection
{
__block int value = 0;
[self readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
value = [[transaction objectForKey:key inCollection:collection] intValue];
value++;
[transaction setObject:@(value) forKey:key inCollection:collection];
}];
return value;
}
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection
{
[self setObject:@(value.timeIntervalSince1970) forKey:key inCollection:collection];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,43 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <YapDatabase/YapDatabaseTransaction.h>
@class ECKeyPair;
@class PreKeyRecord;
@class PreKeyBundle;
@class SignedPreKeyRecord;
NS_ASSUME_NONNULL_BEGIN
@interface YapDatabaseReadTransaction (OWS)
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue;
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue;
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSDictionary *)dictionaryForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection;
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection;
@end
#pragma mark -
@interface YapDatabaseReadWriteTransaction (OWS)
#pragma mark - Debug
#if DEBUG
- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath;
- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath;
#endif
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection;
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,116 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "YapDatabaseTransaction+OWS.h"
#import <Curve25519Kit/Curve25519.h>
NS_ASSUME_NONNULL_BEGIN
@implementation YapDatabaseReadTransaction (OWS)
- (nullable id)objectForKey:(NSString *)key inCollection:(NSString *)collection ofExpectedType:(Class) class {
id _Nullable value = [self objectForKey:key inCollection:collection];
return value;
}
- (nullable NSDictionary *)dictionaryForKey : (NSString *)key inCollection : (NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSDictionary class]];
}
- (nullable NSString *)stringForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSString class]];
}
- (BOOL)boolForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(BOOL)defaultValue
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return value ? [value boolValue] : defaultValue;
}
- (double)doubleForKey:(NSString *)key inCollection:(NSString *)collection defaultValue:(double)defaultValue
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return value ? [value doubleValue] : defaultValue;
}
- (nullable NSData *)dataForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[NSData class]];
}
- (nullable ECKeyPair *)keyPairForKey:(NSString *)key inCollection:(NSString *)collection
{
return [self objectForKey:key inCollection:collection ofExpectedType:[ECKeyPair class]];
}
- (int)intForKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable number = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
return [number intValue];
}
- (nullable NSDate *)dateForKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable value = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
if (value) {
return [NSDate dateWithTimeIntervalSince1970:value.doubleValue];
} else {
return nil;
}
}
@end
#pragma mark -
@implementation YapDatabaseReadWriteTransaction (OWS)
#pragma mark - Debug
#if DEBUG
- (void)snapshotCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath
{
NSMutableDictionary<NSString *, id> *snapshot = [NSMutableDictionary new];
[self enumerateKeysAndObjectsInCollection:collection
usingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
snapshot[key] = value;
}];
NSData *_Nullable data = [NSKeyedArchiver archivedDataWithRootObject:snapshot];
BOOL success = [data writeToFile:snapshotFilePath atomically:YES];
}
- (void)restoreSnapshotOfCollection:(NSString *)collection snapshotFilePath:(NSString *)snapshotFilePath
{
NSData *_Nullable data = [NSData dataWithContentsOfFile:snapshotFilePath];
NSMutableDictionary<NSString *, id> *_Nullable snapshot = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[self removeAllObjectsInCollection:collection];
[snapshot enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull value, BOOL *_Nonnull stop) {
[self setObject:value forKey:key inCollection:collection];
}];
}
#endif
- (void)setBool:(BOOL)value forKey:(NSString *)key inCollection:(NSString *)collection
{
NSNumber *_Nullable oldValue = [self objectForKey:key inCollection:collection ofExpectedType:[NSNumber class]];
if (oldValue && [@(value) isEqual:oldValue]) {
// Skip redundant writes.
return;
}
[self setObject:@(value) forKey:key inCollection:collection];
}
- (void)setDate:(NSDate *)value forKey:(NSString *)key inCollection:(NSString *)collection
{
[self setObject:@(value.timeIntervalSince1970) forKey:key inCollection:collection];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -125,8 +125,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
completion()
}
)
NotificationCenter.default.addObserver(self, selector: #selector(storageIsReady), name: .StorageIsReady, object: nil)
}
@objc
@ -145,13 +143,6 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
checkIsAppReady()
}
@objc
private func storageIsReady() {
AssertIsOnMainThread()
checkIsAppReady()
}
@objc
private func checkIsAppReady() {
AssertIsOnMainThread()
@ -160,7 +151,7 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
guard !AppReadiness.isAppReady() else { return }
// App isn't ready until storage is ready AND all version migrations are complete.
guard OWSStorage.isStorageReady() && areVersionMigrationsComplete else { return }
guard GRDBStorage.shared.isValid && areVersionMigrationsComplete else { return }
SignalUtilitiesKit.Configuration.performMainSetup()

View File

@ -56,13 +56,6 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
)
// We don't need to use "screen protection" in the SAE.
NotificationCenter.default.addObserver(
self,
selector: #selector(storageIsReady),
name: .StorageIsReady,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidEnterBackground),
@ -89,22 +82,13 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
checkIsAppReady()
}
@objc
func storageIsReady() {
AssertIsOnMainThread()
Logger.debug("")
checkIsAppReady()
}
@objc
func checkIsAppReady() {
AssertIsOnMainThread()
// App isn't ready until storage is ready AND all version migrations are complete.
guard areVersionMigrationsComplete else { return }
guard OWSStorage.isStorageReady() else { return }
guard GRDBStorage.shared.isValid else { return }
guard !AppReadiness.isAppReady() else {
// Only mark the app as ready once.
return

View File

@ -3,10 +3,6 @@
import Foundation
import SessionUtilitiesKit
public struct SNSnodeKitConfiguration {
internal static var shared: SNSnodeKitConfiguration!
}
public enum SNSnodeKit { // Just to make the external API nice
public static func migrations() -> TargetMigrations {
return TargetMigrations(

View File

@ -2,6 +2,7 @@
import Foundation
import GRDB
import YapDatabase
import SessionUtilitiesKit
enum _003_YDBToGRDBMigration: Migration {

View File

@ -1,13 +1,14 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
@objc
public final class SNUtilitiesKitConfiguration : NSObject {
@objc public let owsPrimaryStorage: OWSPrimaryStorageProtocol
public let maxFileSize: UInt
@objc public static var shared: SNUtilitiesKitConfiguration!
fileprivate init(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) {
self.owsPrimaryStorage = owsPrimaryStorage
fileprivate init(maxFileSize: UInt) {
self.maxFileSize = maxFileSize
}
}
@ -29,7 +30,7 @@ public enum SNUtilitiesKit { // Just to make the external API nice
)
}
public static func configure(owsPrimaryStorage: OWSPrimaryStorageProtocol, maxFileSize: UInt) {
SNUtilitiesKitConfiguration.shared = SNUtilitiesKitConfiguration(owsPrimaryStorage: owsPrimaryStorage, maxFileSize: maxFileSize)
public static func configure(maxFileSize: UInt) {
SNUtilitiesKitConfiguration.shared = SNUtilitiesKitConfiguration(maxFileSize: maxFileSize)
}
}

View File

@ -257,7 +257,7 @@ public final class GRDBStorage {
// MARK: - File Management
private static func resetAllStorage() {
public static func resetAllStorage() {
NotificationCenter.default.post(name: .resetStorage, object: nil)
// This might be redundant but in the spirit of thoroughness...

View File

@ -2,6 +2,7 @@
import Foundation
import GRDB
import YapDatabase
enum _003_YDBToGRDBMigration: Migration {
static let target: TargetMigrations.Identifier = .utilitiesKit

View File

@ -1,7 +0,0 @@
import YapDatabase
@objc public protocol OWSPrimaryStorageProtocol {
var dbReadConnection: YapDatabaseConnection { get }
var dbReadWriteConnection: YapDatabaseConnection { get }
}

View File

@ -1,71 +0,0 @@
import PromiseKit
import YapDatabase
// Some important notes about YapDatabase:
//
// Connections are thread-safe.
// Executing a write transaction from within a write transaction is NOT allowed.
@objc(LKStorage)
public final class Storage : NSObject {
public static let serialQueue = DispatchQueue(label: "Storage.serialQueue", qos: .userInitiated)
private static var owsStorage: OWSPrimaryStorageProtocol { SNUtilitiesKitConfiguration.shared.owsPrimaryStorage }
@objc public static let shared = Storage()
// MARK: Reading
// Some important points regarding reading from the database:
//
// Background threads should use `OWSPrimaryStorage`'s `dbReadConnection`, whereas the main thread should use `OWSPrimaryStorage`'s `uiDatabaseConnection` (see the `YapDatabaseConnectionPool` documentation for more information).
// Multiple read transactions can safely be executed at the same time.
@objc(readWithBlock:)
public static func read(with block: @escaping (YapDatabaseReadTransaction) -> Void) {
owsStorage.dbReadConnection.read(block)
}
// MARK: Writing
// Some important points regarding writing to the database:
//
// There can only be a single write transaction per database at any one time, so all write transactions must use `OWSPrimaryStorage`'s `dbReadWriteConnection`.
// Executing a write transaction from within a write transaction causes a deadlock and must be avoided.
@discardableResult
@objc(writeWithBlock:)
public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> AnyPromise {
return AnyPromise.from(write(with: block) { })
}
@discardableResult
public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise<Void> {
return write(with: block) { }
}
@discardableResult
@objc(writeWithBlock:completion:)
public static func objc_write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> AnyPromise {
return AnyPromise.from(write(with: block, completion: completion))
}
@discardableResult
public static func write(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void, completion: @escaping () -> Void) -> Promise<Void> {
let (promise, seal) = Promise<Void>.pending()
serialQueue.async {
owsStorage.dbReadWriteConnection.readWrite { transaction in
transaction.addCompletionQueue(DispatchQueue.main, completionBlock: completion)
block(transaction)
}
seal.fulfill(())
}
return promise
}
/// Blocks the calling thread until the write has finished.
@objc(writeSyncWithBlock:)
public static func writeSync(with block: @escaping (YapDatabaseReadWriteTransaction) -> Void) {
try! write(with: block, completion: { }).wait() // The promise returned by write(with:completion:) never rejects
}
}

View File

@ -1,165 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <YapDatabase/YapDatabase.h>
#import <Mantle/MTLModel+NSCoding.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSPrimaryStorage;
@class YapDatabaseConnection;
@class YapDatabaseReadTransaction;
@class YapDatabaseReadWriteTransaction;
@interface TSYapDatabaseObject : MTLModel
- (instancetype)init NS_DESIGNATED_INITIALIZER;
/**
* Initializes a new database object with a unique identifier
*
* @param uniqueId Key used for the key-value store
*
* @return Initialized object
*/
- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
/**
* Returns the collection to which the object belongs.
*
* @return Key (string) identifying the collection
*/
+ (NSString *)collection;
/**
* Get the number of keys in the models collection. Be aware that if there
* are multiple object types in this collection that the count will include
* the count of other objects in the same collection.
*
* @return The number of keys in the classes collection.
*/
+ (NSUInteger)numberOfKeysInCollection;
+ (NSUInteger)numberOfKeysInCollectionWithTransaction:(YapDatabaseReadTransaction *)transaction;
/**
* Removes all objects in the classes collection.
*/
+ (void)removeAllObjectsInCollection;
/**
* A memory intesive method to get all objects in the collection. You should prefer using enumeration over this method
* whenever feasible. See `enumerateObjectsInCollectionUsingBlock`
*
* @return All objects in the classes collection.
*/
+ (NSArray *)allObjectsInCollection;
/**
* Enumerates all objects in collection.
*/
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block;
+ (void)enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction
usingBlock:(void (^)(id object, BOOL *stop))block;
/**
* @return Shared database connections for reading and writing.
*/
- (YapDatabaseConnection *)dbReadConnection;
+ (YapDatabaseConnection *)dbReadConnection;
- (YapDatabaseConnection *)dbReadWriteConnection;
+ (YapDatabaseConnection *)dbReadWriteConnection;
/**
* Fetches the object with the provided identifier
*
* @param uniqueID Unique identifier of the entry in a collection
* @param transaction Transaction used for fetching the object
*
* @return Instance of the object or nil if non-existent
*/
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
transaction:(YapDatabaseReadTransaction *)transaction
NS_SWIFT_NAME(fetch(uniqueId:transaction:));
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID NS_SWIFT_NAME(fetch(uniqueId:));
/**
* Saves the object with the shared readWrite connection.
*
* This method will block if another readWrite transaction is open.
*/
- (void)save;
/**
* Assign the latest persisted values from the database.
*/
- (void)reload;
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction;
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing;
/**
* Saves the object with the shared readWrite connection - does not block.
*
* Be mindful that this method may clobber other changes persisted
* while waiting to open the readWrite transaction.
*
* @param completionBlock is called on the main thread
*/
- (void)saveAsyncWithCompletionBlock:(void (^_Nullable)(void))completionBlock;
/**
* Saves the object with the provided transaction
*
* @param transaction Database transaction
*/
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
/**
* `touch` is a cheap way to fire a YapDatabaseModified notification to redraw anythign depending on the model.
*/
- (void)touch;
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
/**
* The unique identifier of the stored object
*/
@property (nonatomic, nullable) NSString *uniqueId;
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)remove;
#pragma mark - Update With...
// This method is used by "updateWith..." methods.
//
// This model may be updated from many threads. We don't want to save
// our local copy (this instance) since it may be out of date. We also
// want to avoid re-saving a model that has been deleted. Therefore, we
// use "updateWith..." methods to:
//
// a) Update a property of this instance.
// b) If a copy of this model exists in the database, load an up-to-date copy,
// and update and save that copy.
// b) If a copy of this model _DOES NOT_ exist in the database, do _NOT_ save
// this local instance.
//
// After "updateWith...":
//
// a) Any copy of this model in the database will have been updated.
// b) The local property on this instance will always have been updated.
// c) Other properties on this instance may be out of date.
//
// All mutable properties of this class have been made read-only to
// prevent accidentally modifying them directly.
//
// This isn't a perfect arrangement, but in practice this will prevent
// data loss and will resolve all known issues.
- (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction
changeBlock:(void (^)(id))changeBlock;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,229 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "TSYapDatabaseObject.h"
#import <YapDatabase/YapDatabaseTransaction.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
@implementation TSYapDatabaseObject
- (instancetype)init
{
return [self initWithUniqueId:[[NSUUID UUID] UUIDString]];
}
- (instancetype)initWithUniqueId:(NSString *_Nullable)aUniqueId
{
self = [super init];
if (!self) {
return self;
}
_uniqueId = aUniqueId;
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (!self) {
return self;
}
return self;
}
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
[transaction setObject:self forKey:self.uniqueId inCollection:[[self class] collection]];
}
- (void)save
{
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self saveWithTransaction:transaction];
}];
}
- (void)saveAsyncWithCompletionBlock:(void (^_Nullable)(void))completionBlock
{
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[self saveWithTransaction:transaction];
} completion:completionBlock];
}
- (void)touchWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
[transaction touchObjectForKey:self.uniqueId inCollection:[self.class collection]];
}
- (void)touch
{
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self touchWithTransaction:transaction];
}];
}
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
[transaction removeObjectForKey:self.uniqueId inCollection:[[self class] collection]];
}
- (void)remove
{
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self removeWithTransaction:transaction];
}];
}
- (YapDatabaseConnection *)dbReadConnection
{
return [[self class] dbReadConnection];
}
- (YapDatabaseConnection *)dbReadWriteConnection
{
return [[self class] dbReadWriteConnection];
}
#pragma mark Class Methods
+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey
{
if ([propertyKey isEqualToString:@"TAG"]) {
return MTLPropertyStorageNone;
} else {
return [super storageBehaviorForPropertyWithKey:propertyKey];
}
}
+ (YapDatabaseConnection *)dbReadConnection
{
// We use TSYapDatabaseObject's dbReadWriteConnection (not OWSPrimaryStorage's
// dbReadConnection) for consistency, since we tend to [TSYapDatabaseObject
// save] and want to write to the same connection we read from. To get true
// consistency, we'd want to update entities by reading & writing from within
// the same transaction, but that'll be a big refactor.
return self.dbReadWriteConnection;
}
+ (YapDatabaseConnection *)dbReadWriteConnection
{
return SNUtilitiesKitConfiguration.shared.owsPrimaryStorage.dbReadWriteConnection;
}
+ (NSString *)collection
{
return NSStringFromClass([self class]);
}
+ (NSUInteger)numberOfKeysInCollection
{
__block NSUInteger count;
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
count = [self numberOfKeysInCollectionWithTransaction:transaction];
}];
return count;
}
+ (NSUInteger)numberOfKeysInCollectionWithTransaction:(YapDatabaseReadTransaction *)transaction
{
return [transaction numberOfKeysInCollection:[self collection]];
}
+ (NSArray *)allObjectsInCollection
{
__block NSMutableArray *all = [[NSMutableArray alloc] initWithCapacity:[self numberOfKeysInCollection]];
[self enumerateCollectionObjectsUsingBlock:^(id object, BOOL *stop) {
[all addObject:object];
}];
return [all copy];
}
+ (void)enumerateCollectionObjectsUsingBlock:(void (^)(id object, BOOL *stop))block
{
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self enumerateCollectionObjectsWithTransaction:transaction usingBlock:block];
}];
}
+ (void)enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction
usingBlock:(void (^)(id object, BOOL *stop))block
{
// Ignoring most of the YapDB parameters, and just passing through the ones we usually use.
void (^yapBlock)(NSString *key, id object, id metadata, BOOL *stop)
= ^void(NSString *key, id object, id metadata, BOOL *stop) {
block(object, stop);
};
[transaction enumerateRowsInCollection:[self collection] usingBlock:yapBlock];
}
+ (void)removeAllObjectsInCollection
{
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeAllObjectsInCollection:[self collection]];
}];
}
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
transaction:(YapDatabaseReadTransaction *)transaction
{
return [transaction objectForKey:uniqueID inCollection:[self collection]];
}
+ (nullable instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID
{
__block id _Nullable object = nil;
[[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *transaction) {
object = [transaction objectForKey:uniqueID inCollection:[self collection]];
}];
return object;
}
#pragma mark - Update With...
- (void)applyChangeToSelfAndLatestCopy:(YapDatabaseReadWriteTransaction *)transaction
changeBlock:(void (^)(id))changeBlock
{
changeBlock(self);
NSString *collection = [[self class] collection];
id latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
if (latestInstance) {
changeBlock(latestInstance);
[latestInstance saveWithTransaction:transaction];
}
}
#pragma mark Reload
- (void)reload
{
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[self reloadWithTransaction:transaction];
}];
}
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction
{
[self reloadWithTransaction:transaction ignoreMissing:NO];
}
- (void)reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing
{
TSYapDatabaseObject *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
if (!latest) {
return;
}
[self setValuesForKeysWithDictionary:latest.dictionaryValue];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -15,7 +15,6 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[];
#import <SessionUtilitiesKit/OWSFileSystem.h>
#import <SessionUtilitiesKit/OWSMath.h>
#import <SessionUtilitiesKit/TSRequest.h>
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
#import <SessionUtilitiesKit/UIImage+OWS.h>
#import <SessionUtilitiesKit/UIView+OWS.h>

View File

@ -1,20 +1,14 @@
import SessionMessagingKit
import SessionSnodeKit
extension OWSPrimaryStorage : OWSPrimaryStorageProtocol { }
@objc(SNConfiguration)
public final class Configuration : NSObject {
@objc public static func performMainSetup() {
public enum Configuration {
public static func performMainSetup() {
// Need to do this first to ensure the legacy database exists
SNUtilitiesKit.configure(
owsPrimaryStorage: OWSPrimaryStorage.shared(),
maxFileSize: UInt(Double(FileServerAPIV2.maxFileSize) / FileServerAPIV2.fileSizeORMultiplier)
)
SNMessagingKit.configure(storage: Storage.shared)
SNMessagingKit.configure()
SNSnodeKit.configure()
}
}

View File

@ -1,52 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation
import PromiseKit
public extension YapDatabaseConnection {
@objc
func readWritePromise(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> AnyPromise {
return AnyPromise(readWritePromise(block) as Promise<Void>)
}
func readWritePromise(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) -> Promise<Void> {
return Promise { resolver in
self.asyncReadWrite(block, completionBlock: { resolver.fulfill(()) })
}
}
func read(_ block: @escaping (YapDatabaseReadTransaction) throws -> Void) throws {
var errorToRaise: Error?
read { transaction in
do {
try block(transaction)
} catch {
errorToRaise = error
}
}
if let errorToRaise = errorToRaise {
throw errorToRaise
}
}
func readWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) throws -> Void) throws {
var errorToRaise: Error?
readWrite { transaction in
do {
try block(transaction)
} catch {
errorToRaise = error
}
}
if let errorToRaise = errorToRaise {
throw errorToRaise
}
}
}

View File

@ -25,13 +25,10 @@ public enum AppSetup {
// All of these "singletons" should have any dependencies used in their
// initializers injected.
OWSBackgroundTaskManager.shared().observeNotifications()
let primaryStorage: OWSPrimaryStorage = OWSPrimaryStorage(storage: ())
OWSPrimaryStorage.protectFiles()
// AFNetworking (via CFNetworking) spools it's attachments to NSTemporaryDirectory().
// If you receive a media message while the device is locked, the download will fail if the temporary directory
// is NSFileProtectionComplete
// If you receive a media message while the device is locked, the download will fail if
// the temporary directory is NSFileProtectionComplete
let success: Bool = OWSFileSystem.protectFileOrFolder(
atPath: NSTemporaryDirectory(),
fileProtectionType: .completeUntilFirstUserAuthentication
@ -39,10 +36,8 @@ public enum AppSetup {
assert(success)
Environment.shared = Environment(
primaryStorage: primaryStorage,
reachabilityManager: SSKReachabilityManagerImpl(),
audioSession: OWSAudioSession(),
preferences: OWSPreferences(),
proximityMonitoringManager: OWSProximityMonitoringManagerImpl(),
windowManager: OWSWindowManager(default: ())
)

View File

@ -3,6 +3,7 @@
//
import Foundation
import SessionUtilitiesKit
@objc public class OWSAlerts: NSObject {
@ -93,32 +94,4 @@ import Foundation
action.accessibilityIdentifier = "OWSAlerts.\("cancel")"
return action
}
@objc
public class func showIOSUpgradeNagIfNecessary() {
// Our min SDK is iOS9, so this will only show for iOS9 users
if #available(iOS 10.0, *) {
return
}
// Don't show the nag to users who have just launched
// the app for the first time.
guard AppVersion.sharedInstance().lastAppVersion != nil else {
return
}
if let iOSUpgradeNagDate = Environment.shared.preferences.iOSUpgradeNagDate() {
let kNagFrequencySeconds = 14 * kDayInterval
guard fabs(iOSUpgradeNagDate.timeIntervalSinceNow) > kNagFrequencySeconds else {
return
}
}
Environment.shared.preferences.setIOSUpgradeNagDate(Date())
OWSAlerts.showAlert(title: NSLocalizedString("UPGRADE_IOS_ALERT_TITLE",
comment: "Title for the alert indicating that user should upgrade iOS."),
message: NSLocalizedString("UPGRADE_IOS_ALERT_MESSAGE",
comment: "Message for the alert indicating that user should upgrade iOS."))
}
}