Merge pull request #330 from loki-project/attachments-fix

Fix Attachments Sometimes Not Downloading
pull/331/head
Niels Andriesse 4 years ago committed by GitHub
commit 2f906d8bb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -277,6 +277,8 @@
B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; };
B8A14D702589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */; };
B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */; };
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */; };
B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8B26C8F234D629C004ED98C /* MentionCandidateSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */; };
B8B32021258B1A650020074B /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32020258B1A650020074B /* Contact.swift */; };
B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8B32032258B235D0020074B /* Storage+Contacts.swift */; };
@ -303,7 +305,6 @@
C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */; };
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5BC2554B00D00555489 /* ReadReceipt.swift */; };
C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5D22554B05A00555489 /* TypingIndicator.swift */; };
C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5DC2554B06600555489 /* ClosedGroupUpdate.swift */; };
C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */; };
C300A5F22554B09800555489 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5F12554B09800555489 /* MessageSender.swift */; };
C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5FB2554B0A000555489 /* MessageReceiver.swift */; };
@ -490,7 +491,6 @@
C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; };
C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB78255A581000E217F9 /* OWSOperation.m */; };
C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; };
C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB87255A581100E217F9 /* JobQueue.swift */; };
C33FDD45255A582000E217F9 /* Storage+SessionManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */; };
C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; };
C33FDD53255A582000E217F9 /* OWSPrimaryStorage+keyFromIntLong.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB99255A581300E217F9 /* OWSPrimaryStorage+keyFromIntLong.m */; };
@ -687,9 +687,6 @@
C396DAF42518408B00FF6DC5 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAED2518408B00FF6DC5 /* Parser.swift */; };
C396DAF52518408B00FF6DC5 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = C396DAEE2518408B00FF6DC5 /* CSV.swift */; };
C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */; };
C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */; };
C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDACD255A580200E217F9 /* SSKJobRecord.m */; };
C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */; };
C3A3A0F5256E194C004D228D /* OWSRecipientIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAA0255A57FF00E217F9 /* OWSRecipientIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB20255A580900E217F9 /* TSDatabaseSecondaryIndexes.m */; };
@ -979,7 +976,7 @@
34480B341FD0929200BC14EF /* ShareAppExtensionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareAppExtensionContext.h; sourceTree = "<group>"; };
34480B351FD0929200BC14EF /* ShareAppExtensionContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShareAppExtensionContext.m; sourceTree = "<group>"; };
34480B371FD092A900BC14EF /* SignalShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SignalShareExtension-Bridging-Header.h"; sourceTree = "<group>"; };
34480B381FD092E300BC14EF /* SignalShareExtension-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SignalShareExtension-Prefix.pch"; sourceTree = "<group>"; };
34480B381FD092E300BC14EF /* SessionShareExtension-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SessionShareExtension-Prefix.pch"; sourceTree = "<group>"; };
344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOrphanDataCleaner.h; sourceTree = "<group>"; };
344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOrphanDataCleaner.m; sourceTree = "<group>"; };
3461284A1FD0B93F00532771 /* SAELoadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAELoadViewController.swift; sourceTree = "<group>"; };
@ -1265,6 +1262,8 @@
B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = "<group>"; };
B8A14D6F2589CE9000E70D57 /* KeyPairMigrationSuccessSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairMigrationSuccessSheet.swift; sourceTree = "<group>"; };
B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Trimming.swift"; sourceTree = "<group>"; };
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneralUtilities.h; sourceTree = "<group>"; };
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneralUtilities.m; sourceTree = "<group>"; };
B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionCandidateSelectionView.swift; sourceTree = "<group>"; };
B8B32020258B1A650020074B /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = "<group>"; };
B8B32032258B235D0020074B /* Storage+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Storage+Contacts.swift"; sourceTree = "<group>"; };
@ -1311,7 +1310,6 @@
C300A5B12554AF9800555489 /* VisibleMessage+Profile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Profile.swift"; sourceTree = "<group>"; };
C300A5BC2554B00D00555489 /* ReadReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadReceipt.swift; sourceTree = "<group>"; };
C300A5D22554B05A00555489 /* TypingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingIndicator.swift; sourceTree = "<group>"; };
C300A5DC2554B06600555489 /* ClosedGroupUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosedGroupUpdate.swift; sourceTree = "<group>"; };
C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpirationTimerUpdate.swift; sourceTree = "<group>"; };
C300A5F12554B09800555489 /* MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSender.swift; sourceTree = "<group>"; };
C300A5FB2554B0A000555489 /* MessageReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiver.swift; sourceTree = "<group>"; };
@ -1381,7 +1379,6 @@
C33FDAC2255A580200E217F9 /* TSAttachment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachment.m; sourceTree = "<group>"; };
C33FDAC3255A580200E217F9 /* OWSDispatch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDispatch.m; sourceTree = "<group>"; };
C33FDAC4255A580200E217F9 /* TSAttachmentStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentStream.m; sourceTree = "<group>"; };
C33FDACD255A580200E217F9 /* SSKJobRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKJobRecord.m; sourceTree = "<group>"; };
C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAttachmentDownloads.h; sourceTree = "<group>"; };
C33FDAD3255A580300E217F9 /* TSThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSThread.h; sourceTree = "<group>"; };
C33FDAD5255A580300E217F9 /* TSQuotedMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSQuotedMessage.h; sourceTree = "<group>"; };
@ -1440,7 +1437,6 @@
C33FDB48255A580C00E217F9 /* TSOutgoingMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSOutgoingMessage.h; 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>"; };
C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKJobRecord.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>"; };
C33FDB56255A580D00E217F9 /* TSOutgoingMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSOutgoingMessage.m; sourceTree = "<group>"; };
@ -1468,7 +1464,6 @@
C33FDB81255A581100E217F9 /* UIImage+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+OWS.m"; sourceTree = "<group>"; };
C33FDB83255A581100E217F9 /* TSQuotedMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSQuotedMessage.m; sourceTree = "<group>"; };
C33FDB85255A581100E217F9 /* AppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppContext.m; sourceTree = "<group>"; };
C33FDB87255A581100E217F9 /* JobQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JobQueue.swift; sourceTree = "<group>"; };
C33FDB88255A581200E217F9 /* TSAccountManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAccountManager.m; sourceTree = "<group>"; };
C33FDB8A255A581200E217F9 /* AppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppContext.h; sourceTree = "<group>"; };
C33FDB8B255A581200E217F9 /* Storage+SessionManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Storage+SessionManagement.swift"; sourceTree = "<group>"; };
@ -1723,7 +1718,6 @@
C396DAED2518408B00FF6DC5 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; };
C396DAEE2518408B00FF6DC5 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = "<group>"; };
C39DD28724F3318C008590FC /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = "<group>"; };
C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKJobRecordFinder.swift; sourceTree = "<group>"; };
C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKReachabilityManager.swift; sourceTree = "<group>"; };
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageWrapper.swift; sourceTree = "<group>"; };
C3A71D1C25589AC30043A11F /* WebSocketProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketProto.swift; sourceTree = "<group>"; };
@ -1819,9 +1813,9 @@
D221A08D169C9E5E00537ABF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
D221A08F169C9E5E00537ABF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
D221A091169C9E5E00537ABF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
D221A095169C9E5E00537ABF /* Signal-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Signal-Info.plist"; sourceTree = "<group>"; };
D221A095169C9E5E00537ABF /* Session-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Session-Info.plist"; sourceTree = "<group>"; };
D221A099169C9E5E00537ABF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
D221A09B169C9E5E00537ABF /* Signal-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Prefix.pch"; sourceTree = "<group>"; };
D221A09B169C9E5E00537ABF /* Session-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Session-Prefix.pch"; sourceTree = "<group>"; };
D221A0E7169DFFC500537ABF /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = ../../../../../../System/Library/Frameworks/AVFoundation.framework; sourceTree = "<group>"; };
D24B5BD4169F568C00681372 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = ../../../../../../System/Library/Frameworks/AudioToolbox.framework; sourceTree = "<group>"; };
D2AEACDB16C426DA00C364C0 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
@ -2554,7 +2548,6 @@
C3C2A7702553A41E00C340D1 /* ControlMessage.swift */,
C300A5BC2554B00D00555489 /* ReadReceipt.swift */,
C300A5D22554B05A00555489 /* TypingIndicator.swift */,
C300A5DC2554B06600555489 /* ClosedGroupUpdate.swift */,
C34A977325A3E34A00852C71 /* ClosedGroupUpdateV2.swift */,
C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */,
);
@ -2601,7 +2594,7 @@
4535186F1FC635DD00210559 /* Info.plist */,
34B0796E1FD07B1E00E248C2 /* SignalShareExtension.entitlements */,
34480B371FD092A900BC14EF /* SignalShareExtension-Bridging-Header.h */,
34480B381FD092E300BC14EF /* SignalShareExtension-Prefix.pch */,
34480B381FD092E300BC14EF /* SessionShareExtension-Prefix.pch */,
);
path = Meta;
sourceTree = "<group>";
@ -2745,8 +2738,8 @@
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */,
C33FDC02255A581D00E217F9 /* OWSPrimaryStorage.m */,
C33FDAFE255A580600E217F9 /* OWSStorage.h */,
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */,
C33FDAB1255A580000E217F9 /* OWSStorage.m */,
C33FDAB9255A580100E217F9 /* OWSStorage+Subclass.h */,
B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */,
B8B32032258B235D0020074B /* Storage+Contacts.swift */,
B8D8F17625661AFA0092EF10 /* Storage+Jobs.swift */,
@ -2878,7 +2871,6 @@
C38EF286255B6D85007E1867 /* VersionMigrations.m */,
C33FDA8B255A57FD00E217F9 /* AppVersion.m */,
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */,
C33FDB87255A581100E217F9 /* JobQueue.swift */,
C33FDA99255A57FE00E217F9 /* OutageDetection.swift */,
C33FDACF255A580300E217F9 /* OWSAttachmentDownloads.h */,
C33FDC13255A581E00E217F9 /* OWSAttachmentDownloads.m */,
@ -3161,6 +3153,8 @@
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */,
C33FDB7F255A581100E217F9 /* FullTextSearchFinder.swift */,
C33FDBC1255A581700E217F9 /* General.swift */,
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */,
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */,
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */,
C3A71D4825589FF20043A11F /* NSData+messagePadding.m */,
@ -3192,9 +3186,6 @@
C33FDB31255A580A00E217F9 /* SSKEnvironment.h */,
C33FDAF4255A580600E217F9 /* SSKEnvironment.m */,
C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */,
C33FDB4F255A580D00E217F9 /* SSKJobRecord.h */,
C33FDACD255A580200E217F9 /* SSKJobRecord.m */,
C3A3A098256E17B2004D228D /* SSKJobRecordFinder.swift */,
C3A3A170256E1D25004D228D /* SSKReachabilityManager.swift */,
C3ECBF7A257056B700EA7FCE /* Threading.swift */,
C33FDB5F255A580E00E217F9 /* YapDatabaseConnection+OWS.h */,
@ -3421,8 +3412,8 @@
B67EBF5C19194AC60084CCFD /* Settings.bundle */,
B657DDC91911A40500F45B0C /* Signal.entitlements */,
45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */,
D221A095169C9E5E00537ABF /* Signal-Info.plist */,
D221A09B169C9E5E00537ABF /* Signal-Prefix.pch */,
D221A095169C9E5E00537ABF /* Session-Info.plist */,
D221A09B169C9E5E00537ABF /* Session-Prefix.pch */,
4C63CBFF210A620B003AE45C /* SignalTSan.supp */,
4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */,
34074F54203D0722004596AE /* Sounds */,
@ -3667,7 +3658,6 @@
C32C5ADF256DBFAA003C73A2 /* OWSReadTracking.h in Headers */,
C3D9E486256775D20040E4F3 /* TSAttachmentPointer.h in Headers */,
C32C5EF7256DF567003C73A2 /* TSDatabaseView.h in Headers */,
C3A3A0B3256E17F2004D228D /* SSKJobRecord.h in Headers */,
B8856ED7256F1EB4001CE70E /* OWSPreferences.h in Headers */,
C32A026C25A801AF000ED5D4 /* NSData+messagePadding.h in Headers */,
C32C5BE6256DC891003C73A2 /* OWSReadReceiptManager.h in Headers */,
@ -3675,6 +3665,7 @@
C32C5BF8256DC8F6003C73A2 /* OWSDisappearingMessagesJob.h in Headers */,
C32C5AAA256DBE8F003C73A2 /* TSIncomingMessage.h in Headers */,
B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */,
B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */,
C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */,
C32C5F23256DFCC0003C73A2 /* TSErrorMessage_privateConstructor.h in Headers */,
C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */,
@ -3998,7 +3989,7 @@
};
};
};
buildConfigurationList = D221A083169C9E5E00537ABF /* Build configuration list for PBXProject "Signal" */;
buildConfigurationList = D221A083169C9E5E00537ABF /* Build configuration list for PBXProject "Session" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
@ -4622,7 +4613,6 @@
C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */,
C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */,
B8B3204E258C15C80020074B /* ContactsMigration.swift in Sources */,
C33FDD41255A582000E217F9 /* JobQueue.swift in Sources */,
C32A025A25A7FC55000ED5D4 /* ClosedGroupsV2Migration.swift in Sources */,
C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */,
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */,
@ -4791,9 +4781,9 @@
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */,
C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */,
C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */,
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */,
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */,
B8B3207B258C22550020074B /* DisplayNameUtilities.swift in Sources */,
C3A3A099256E17B2004D228D /* SSKJobRecordFinder.swift in Sources */,
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */,
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */,
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */,
@ -4809,7 +4799,6 @@
B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */,
C32C5D2E256DD4EA003C73A2 /* TSUnreadIndicatorInteraction.m in Sources */,
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */,
C300A5DD2554B06600555489 /* ClosedGroupUpdate.swift in Sources */,
C3471FA42555439E00297E91 /* Notification+MessageSender.swift in Sources */,
C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */,
C3A7222A2558C1E40043A11F /* DotNetAPI.swift in Sources */,
@ -4858,7 +4847,6 @@
C352A2F525574B4700338F3E /* Job.swift in Sources */,
C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */,
C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */,
C3A3A0AA256E17E6004D228D /* SSKJobRecord.m in Sources */,
C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -5176,7 +5164,7 @@
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SignalShareExtension-Prefix.pch";
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SessionShareExtension-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"COCOAPODS=1",
@ -5246,7 +5234,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SignalShareExtension-Prefix.pch";
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SessionShareExtension-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"COCOAPODS=1",
@ -6395,7 +6383,7 @@
);
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Session/Meta/Signal-Prefix.pch";
GCC_PREFIX_HEADER = "Session/Meta/Session-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
@ -6415,7 +6403,7 @@
"\"$(SRCROOT)/MMDrawerController\"",
"\"$(SRCROOT)/Libraries\"/**",
);
INFOPLIST_FILE = "$(SRCROOT)/Session/Meta/Signal-Info.plist";
INFOPLIST_FILE = "Session/Meta/Session-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
@ -6463,7 +6451,7 @@
);
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Session/Meta/Signal-Prefix.pch";
GCC_PREFIX_HEADER = "Session/Meta/Session-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
HAVE_CONFIG_H,
@ -6483,7 +6471,7 @@
"\"$(SRCROOT)/MMDrawerController\"",
"\"$(SRCROOT)/Libraries\"/**",
);
INFOPLIST_FILE = "$(SRCROOT)/Session/Meta/Signal-Info.plist";
INFOPLIST_FILE = "Session/Meta/Session-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
@ -6581,7 +6569,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = "App Store Release";
};
D221A083169C9E5E00537ABF /* Build configuration list for PBXProject "Signal" */ = {
D221A083169C9E5E00537ABF /* Build configuration list for PBXProject "Session" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D221A0BA169C9E5F00537ABF /* Debug */,

@ -17,7 +17,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@ -47,7 +47,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
@ -65,7 +65,7 @@
BlueprintIdentifier = "D221A0A9169C9E5F00537ABF"
BuildableName = "SignalTests.xctest"
BlueprintName = "SignalTests"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
@ -247,7 +247,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
@ -286,7 +286,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

@ -18,7 +18,7 @@
BlueprintIdentifier = "7BC01A3A241F40AB00BC7C55"
BuildableName = "SessionNotificationServiceExtension.appex"
BlueprintName = "SessionNotificationServiceExtension"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@ -32,7 +32,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@ -63,7 +63,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
@ -81,7 +81,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

@ -18,7 +18,7 @@
BlueprintIdentifier = "453518671FC635DD00210559"
BuildableName = "SessionShareExtension.appex"
BlueprintName = "SessionShareExtension"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
@ -32,7 +32,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@ -48,7 +48,7 @@
BlueprintIdentifier = "453518671FC635DD00210559"
BuildableName = "SessionShareExtension.appex"
BlueprintName = "SessionShareExtension"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
@ -73,7 +73,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
@ -91,7 +91,7 @@
BlueprintIdentifier = "D221A088169C9E5E00537ABF"
BuildableName = "Session.app"
BlueprintName = "Session"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

@ -17,7 +17,7 @@
BlueprintIdentifier = "C33FD9AA255A548A00E217F9"
BuildableName = "SignalUtilitiesKit.framework"
BlueprintName = "SignalUtilitiesKit"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@ -53,7 +53,7 @@
BlueprintIdentifier = "C33FD9AA255A548A00E217F9"
BuildableName = "SignalUtilitiesKit.framework"
BlueprintName = "SignalUtilitiesKit"
ReferencedContainer = "container:Signal.xcodeproj">
ReferencedContainer = "container:Session.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>

@ -2,7 +2,7 @@
<Workspace
version = "1.0">
<FileRef
location = "group:Signal.xcodeproj">
location = "group:/Users/niels/Code/session-ios/Session.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">

@ -389,10 +389,6 @@ static NSTimeInterval launchStartedAt;
// sent before the app exited should be marked as failures.
[[[OWSFailedMessagesJob alloc] initWithPrimaryStorage:self.primaryStorage] run];
[[[OWSFailedAttachmentDownloadsJob alloc] initWithPrimaryStorage:self.primaryStorage] run];
if (CurrentAppContext().isMainApp) {
[SNJobQueue.shared resumePendingJobs];
}
});
}
}); // end dispatchOnce for first time we become active
@ -433,6 +429,10 @@ static NSTimeInterval launchStartedAt;
[OWSSyncPushTokensJob runWithAccountManager:AppEnvironment.shared.accountManager
preferences:Environment.shared.preferences];
}
if (CurrentAppContext().isMainApp) {
[SNJobQueue.shared resumePendingJobs];
}
});
}
}
@ -729,7 +729,7 @@ static NSTimeInterval launchStartedAt;
- (void)startPollerIfNeeded
{
if (self.poller == nil) {
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
if (userPublicKey != nil) {
self.poller = [[LKPoller alloc] init];
}
@ -742,7 +742,7 @@ static NSTimeInterval launchStartedAt;
- (void)startClosedGroupPollerIfNeeded
{
if (self.closedGroupPoller == nil) {
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
if (userPublicKey != nil) {
self.closedGroupPoller = [[LKClosedGroupPoller alloc] init];
}

@ -122,7 +122,7 @@ NS_ASSUME_NONNULL_BEGIN
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
TSContactThread *thread = [outgoingMessage.thread as:TSContactThread.class];
if (thread != nil) {
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
isNoteToSelf = ([thread.contactIdentifier isEqual:userPublicKey]);
}
}];

@ -192,7 +192,7 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4;
}];
innerBubbleView.layer.mask = maskLayer;
if (self.isForPreview) {
NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userHexEncodedPublicKey = [SNGeneralUtilities getUserPublicKey];
BOOL wasSentByUser = [self.quotedMessage.authorId isEqual:userHexEncodedPublicKey];
innerBubbleView.backgroundColor = [self.conversationStyle quotedReplyBubbleColorWithIsIncoming:wasSentByUser];
} else {

@ -554,7 +554,7 @@ typedef enum : NSUInteger {
}
if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).isOpenGroup
&& !((TSGroupThread *)self.thread).usesSharedSenderKeys) {
&& !((TSGroupThread *)self.thread).isClosedGroup) {
self.inputToolbar.hidden = YES;
} else if (self.userLeftGroup) {
self.inputToolbar.hidden = YES; // user has requested they leave the group. further sends disallowed
@ -1190,7 +1190,7 @@ typedef enum : NSUInteger {
[self ensureScrollDownButton];
if ([self.thread isKindOfClass:TSGroupThread.class] && !((TSGroupThread *)self.thread).isOpenGroup
&& !((TSGroupThread *)self.thread).usesSharedSenderKeys) {
&& !((TSGroupThread *)self.thread).isClosedGroup) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Session"
message:@"Legacy closed groups are no longer supported. Please create a new group to continue." preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];

@ -1159,10 +1159,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
return NO;
}
- (NSString *)userHexEncodedPublicKey {
return OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
}
- (BOOL)userCanDeleteGroupMessage
{
if (!self.isGroupThread) return false;
@ -1184,7 +1180,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
if (interationType == OWSInteractionType_IncomingMessage) {
// Only allow deletion on incoming messages if the user has moderation permission
return [SNOpenGroupAPI isUserModerator:self.userHexEncodedPublicKey forChannel:publicChat.channel onServer:publicChat.server];
return [SNOpenGroupAPI isUserModerator:[SNGeneralUtilities getUserPublicKey] forChannel:publicChat.channel onServer:publicChat.server];
} else {
return YES;
}

@ -480,12 +480,12 @@ const CGFloat kIconViewLength = 24;
__block BOOL isUserMember = NO;
if (self.isGroupThread) {
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
isUserMember = [(TSGroupThread *)self.thread isUserMemberInGroup:userPublicKey];
}
if (self.isGroupThread && self.isClosedGroup && isUserMember) {
if (((TSGroupThread *)self.thread).usesSharedSenderKeys) {
if (((TSGroupThread *)self.thread).isClosedGroup) {
[mainSection addItem:[OWSTableItem
itemWithCustomCellBlock:^{
UITableViewCell *cell =
@ -896,7 +896,7 @@ static CGRect oldframe;
- (void)didTapLeaveGroup
{
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
NSString *message;
if ([((TSGroupThread *)self.thread).groupModel.groupAdminIds containsObject:userPublicKey]) {
message = @"Because you are the creator of this group it will be deleted for everyone. This cannot be undone.";
@ -936,7 +936,7 @@ static CGRect oldframe;
{
TSGroupThread *gThread = (TSGroupThread *)self.thread;
if (gThread.usesSharedSenderKeys) {
if (gThread.isClosedGroup) {
NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:gThread.groupModel.groupId];
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[SNMessageSender leaveClosedGroupWithPublicKey:groupPublicKey using:transaction error:nil];

@ -398,7 +398,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol
let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!)
let delete = UITableViewRowAction(style: .destructive, title: NSLocalizedString("TXT_DELETE_TITLE", comment: "")) { [weak self] _, _ in
var message = NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_MESSAGE", comment: "")
if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys, thread.groupModel.groupAdminIds.contains(getUserHexEncodedPublicKey()) {
if let thread = thread as? TSGroupThread, thread.isClosedGroup, thread.groupModel.groupAdminIds.contains(getUserHexEncodedPublicKey()) {
message = "Because you are the creator of this group it will be deleted for everyone. This cannot be undone."
}
let alert = UIAlertController(title: NSLocalizedString("CONVERSATION_DELETE_CONFIRMATION_ALERT_TITLE", comment: ""), message: message, preferredStyle: .alert)
@ -416,7 +416,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol
let _ = OpenGroupAPI.leave(openGroup.channel, on: openGroup.server)
thread.removeAllThreadInteractions(with: transaction)
thread.remove(with: transaction)
} else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys == true {
} else if let thread = thread as? TSGroupThread, thread.isClosedGroup == true {
let groupID = thread.groupModel.groupId
let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID)
do {

@ -179,7 +179,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
[OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:self];
[OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:self];
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:self];
[SSKJobRecordFinder asyncRegisterDatabaseExtensionObjCWithStorage:self];
[self.database
flushExtensionRequestsWithCompletionQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
@ -265,14 +264,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage)
{
// Given how sensitive this migration is, we verbosely
// log the contents of all involved paths before and after.
NSArray<NSString *> *paths = @[
self.legacyDatabaseFilePath,
self.legacyDatabaseFilePath_SHM,
self.legacyDatabaseFilePath_WAL,
self.sharedDataDatabaseFilePath,
self.sharedDataDatabaseFilePath_SHM,
self.sharedDataDatabaseFilePath_WAL,
];
NSFileManager *fileManager = [NSFileManager defaultManager];
// We protect the db files here, which is somewhat redundant with what will happen in

@ -1,197 +0,0 @@
import SessionProtocolKit
import SessionUtilitiesKit
@objc(SNClosedGroupUpdate)
public final class ClosedGroupUpdate : ControlMessage {
public var kind: Kind?
// MARK: Kind
public enum Kind : CustomStringConvertible {
case new(groupPublicKey: Data, name: String, groupPrivateKey: Data, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data])
case info(groupPublicKey: Data, name: String, senderKeys: [ClosedGroupSenderKey], members: [Data], admins: [Data])
case senderKeyRequest(groupPublicKey: Data)
case senderKey(groupPublicKey: Data, senderKey: ClosedGroupSenderKey)
public var description: String {
switch self {
case .new: return "new"
case .info: return "info"
case .senderKeyRequest: return "senderKeyRequest"
case .senderKey: return "senderKey"
}
}
}
// MARK: Initialization
public override init() { super.init() }
internal init(kind: Kind) {
super.init()
self.kind = kind
}
// MARK: Validation
public override var isValid: Bool {
guard super.isValid, let kind = kind else { return false }
switch kind {
case .new(let groupPublicKey, let name, let groupPrivateKey, _, let members, let admins):
return !groupPublicKey.isEmpty && !name.isEmpty && !groupPrivateKey.isEmpty && !members.isEmpty && !admins.isEmpty // senderKeys may be empty
case .info(let groupPublicKey, let name, _, let members, let admins):
return !groupPublicKey.isEmpty && !name.isEmpty && !members.isEmpty && !admins.isEmpty // senderKeys may be empty
case .senderKeyRequest(let groupPublicKey):
return !groupPublicKey.isEmpty
case .senderKey(let groupPublicKey, _):
return !groupPublicKey.isEmpty
}
}
// MARK: Coding
public required init?(coder: NSCoder) {
super.init(coder: coder)
guard let groupPublicKey = coder.decodeObject(forKey: "groupPublicKey") as? Data,
let rawKind = coder.decodeObject(forKey: "kind") as? String else { return }
switch rawKind {
case "new":
guard let name = coder.decodeObject(forKey: "name") as? String,
let groupPrivateKey = coder.decodeObject(forKey: "groupPrivateKey") as? Data,
let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey],
let members = coder.decodeObject(forKey: "members") as? [Data],
let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return }
self.kind = .new(groupPublicKey: groupPublicKey, name: name, groupPrivateKey: groupPrivateKey, senderKeys: senderKeys, members: members, admins: admins)
case "info":
guard let name = coder.decodeObject(forKey: "name") as? String,
let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey],
let members = coder.decodeObject(forKey: "members") as? [Data],
let admins = coder.decodeObject(forKey: "admins") as? [Data] else { return }
self.kind = .info(groupPublicKey: groupPublicKey, name: name, senderKeys: senderKeys, members: members, admins: admins)
case "senderKeyRequest":
self.kind = .senderKeyRequest(groupPublicKey: groupPublicKey)
case "senderKey":
guard let senderKeys = coder.decodeObject(forKey: "senderKeys") as? [ClosedGroupSenderKey],
let senderKey = senderKeys.first else { return }
self.kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: senderKey)
default: return
}
}
public override func encode(with coder: NSCoder) {
super.encode(with: coder)
guard let kind = kind else { return }
switch kind {
case .new(let groupPublicKey, let name, let groupPrivateKey, let senderKeys, let members, let admins):
coder.encode("new", forKey: "kind")
coder.encode(groupPublicKey, forKey: "groupPublicKey")
coder.encode(name, forKey: "name")
coder.encode(groupPrivateKey, forKey: "groupPrivateKey")
coder.encode(senderKeys, forKey: "senderKeys")
coder.encode(members, forKey: "members")
coder.encode(admins, forKey: "admins")
case .info(let groupPublicKey, let name, let senderKeys, let members, let admins):
coder.encode("info", forKey: "kind")
coder.encode(groupPublicKey, forKey: "groupPublicKey")
coder.encode(name, forKey: "name")
coder.encode(senderKeys, forKey: "senderKeys")
coder.encode(members, forKey: "members")
coder.encode(admins, forKey: "admins")
case .senderKeyRequest(let groupPublicKey):
coder.encode(groupPublicKey, forKey: "groupPublicKey")
case .senderKey(let groupPublicKey, let senderKey):
coder.encode("senderKey", forKey: "kind")
coder.encode(groupPublicKey, forKey: "groupPublicKey")
coder.encode([ senderKey ], forKey: "senderKeys")
}
}
// MARK: Proto Conversion
public override class func fromProto(_ proto: SNProtoContent) -> ClosedGroupUpdate? {
guard let closedGroupUpdateProto = proto.dataMessage?.closedGroupUpdate else { return nil }
let groupPublicKey = closedGroupUpdateProto.groupPublicKey
let kind: Kind
switch closedGroupUpdateProto.type {
case .new:
guard let name = closedGroupUpdateProto.name, let groupPrivateKey = closedGroupUpdateProto.groupPrivateKey else { return nil }
let senderKeys = closedGroupUpdateProto.senderKeys.map { ClosedGroupSenderKey.fromProto($0) }
kind = .new(groupPublicKey: groupPublicKey, name: name, groupPrivateKey: groupPrivateKey,
senderKeys: senderKeys, members: closedGroupUpdateProto.members, admins: closedGroupUpdateProto.admins)
case .info:
guard let name = closedGroupUpdateProto.name else { return nil }
let senderKeys = closedGroupUpdateProto.senderKeys.map { ClosedGroupSenderKey.fromProto($0) }
kind = .info(groupPublicKey: groupPublicKey, name: name, senderKeys: senderKeys, members: closedGroupUpdateProto.members, admins: closedGroupUpdateProto.admins)
case .senderKeyRequest:
kind = .senderKeyRequest(groupPublicKey: groupPublicKey)
case .senderKey:
guard let senderKeyProto = closedGroupUpdateProto.senderKeys.first else { return nil }
kind = .senderKey(groupPublicKey: groupPublicKey, senderKey: ClosedGroupSenderKey.fromProto(senderKeyProto))
}
return ClosedGroupUpdate(kind: kind)
}
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {
guard let kind = kind else {
SNLog("Couldn't construct closed group update proto from: \(self).")
return nil
}
do {
let closedGroupUpdate: SNProtoDataMessageClosedGroupUpdate.SNProtoDataMessageClosedGroupUpdateBuilder
switch kind {
case .new(let groupPublicKey, let name, let groupPrivateKey, let senderKeys, let members, let admins):
closedGroupUpdate = SNProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .new)
closedGroupUpdate.setName(name)
closedGroupUpdate.setGroupPrivateKey(groupPrivateKey)
closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() })
closedGroupUpdate.setMembers(members)
closedGroupUpdate.setAdmins(admins)
case .info(let groupPublicKey, let name, let senderKeys, let members, let admins):
closedGroupUpdate = SNProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .info)
closedGroupUpdate.setName(name)
closedGroupUpdate.setSenderKeys(try senderKeys.map { try $0.toProto() })
closedGroupUpdate.setMembers(members)
closedGroupUpdate.setAdmins(admins)
case .senderKeyRequest(let groupPublicKey):
closedGroupUpdate = SNProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKeyRequest)
case .senderKey(let groupPublicKey, let senderKey):
closedGroupUpdate = SNProtoDataMessageClosedGroupUpdate.builder(groupPublicKey: groupPublicKey, type: .senderKey)
closedGroupUpdate.setSenderKeys([ try senderKey.toProto() ])
}
let contentProto = SNProtoContent.builder()
let dataMessageProto = SNProtoDataMessage.builder()
dataMessageProto.setClosedGroupUpdate(try closedGroupUpdate.build())
// Group context
try setGroupContextIfNeeded(on: dataMessageProto, using: transaction)
// Expiration timer
// TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation
// if it receives a message without the current expiration timer value attached to it...
var expiration: UInt32 = 0
if let disappearingMessagesConfiguration = OWSDisappearingMessagesConfiguration.fetch(uniqueId: threadID!, transaction: transaction) {
expiration = disappearingMessagesConfiguration.isEnabled ? disappearingMessagesConfiguration.durationSeconds : 0
}
dataMessageProto.setExpireTimer(expiration)
contentProto.setDataMessage(try dataMessageProto.build())
return try contentProto.build()
} catch {
SNLog("Couldn't construct closed group update proto from: \(self).")
return nil
}
}
// MARK: Description
public override var description: String {
"""
ClosedGroupUpdate(
kind: \(kind?.description ?? "null")
)
"""
}
}
private extension ClosedGroupSenderKey {
static func fromProto(_ proto: SNProtoDataMessageClosedGroupUpdateSenderKey) -> ClosedGroupSenderKey {
return ClosedGroupSenderKey(chainKey: proto.chainKey, keyIndex: UInt(proto.keyIndex), publicKey: proto.publicKey)
}
func toProto() throws -> SNProtoDataMessageClosedGroupUpdateSenderKey {
return try SNProtoDataMessageClosedGroupUpdateSenderKey.builder(chainKey: chainKey, keyIndex: UInt32(keyIndex), publicKey: publicKey).build()
}
}

@ -9,7 +9,7 @@ public extension Message {
static func from(_ thread: TSThread) -> Message.Destination {
if let thread = thread as? TSContactThread {
return .contact(publicKey: thread.contactIdentifier())
} else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys {
} else if let thread = thread as? TSGroupThread, thread.isClosedGroup {
let groupID = thread.groupModel.groupId
let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID)
return .closedGroup(groupPublicKey: groupPublicKey)

@ -49,7 +49,7 @@ public class Message : NSObject, NSCoding { // NSObject/NSCoding conformance is
}
public func setGroupContextIfNeeded(on dataMessage: SNProtoDataMessage.SNProtoDataMessageBuilder, using transaction: YapDatabaseReadTransaction) throws {
guard let thread = TSThread.fetch(uniqueId: threadID!, transaction: transaction) as? TSGroupThread, thread.usesSharedSenderKeys else { return }
guard let thread = TSThread.fetch(uniqueId: threadID!, transaction: transaction) as? TSGroupThread, thread.isClosedGroup else { return }
// Android needs a group context or it'll interpret the message as a one-to-one message
let groupProto = SNProtoGroupContext.builder(id: thread.groupModel.groupId, type: .deliver)
dataMessage.setGroup(try groupProto.build())

@ -23,7 +23,6 @@ public extension TSIncomingMessage {
wasReceivedByUD: true
)
result.openGroupServerMessageID = openGroupServerMessageID
result.isOpenGroupMessage = isOpenGroupMessage
return result
}
}

@ -40,7 +40,6 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value);
@property (nonatomic, readonly) uint64_t sortId;
@property (nonatomic, readonly) uint64_t receivedAtTimestamp;
@property (nonatomic, readonly) BOOL shouldUseServerTime;
@property (nonatomic) BOOL isOpenGroupMessage;
- (void)setServerTimestampToReceivedTimestamp:(uint64_t)receivedAtTimestamp;

@ -199,7 +199,7 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
// In open groups messages should be sorted by server timestamp. `sortId` represents the order in which messages
// were processed. Since in the open group poller we sort messages by their server timestamp, sorting by `sortId` is
// effectively the same as sorting by server timestamp.
if (self.isOpenGroupMessage) {
if ([self isKindOfClass:TSMessage.class] && ((TSMessage *)self).isOpenGroupMessage) {
sortId1 = self.sortId;
sortId2 = other.sortId;
} else {

@ -35,6 +35,7 @@ extern const NSUInteger kOversizeTextMessageSizeThreshold;
@property (nonatomic, readonly, nullable) TSQuotedMessage *quotedMessage;
@property (nonatomic, nullable) OWSLinkPreview *linkPreview;
@property (nonatomic) uint64_t openGroupServerMessageID;
@property (nonatomic, readonly) BOOL isOpenGroupMessage;
- (instancetype)initInteractionWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread NS_UNAVAILABLE;

@ -392,6 +392,11 @@ const NSUInteger kOversizeTextMessageSizeThreshold = 2 * 1024;
[self.quotedMessage setThumbnailAttachmentStream:attachmentStream];
}
- (BOOL)isOpenGroupMessage
{
return (self.openGroupServerMessageID != 0);
}
#pragma mark - Update With... Methods
- (void)updateWithExpireStartedAt:(uint64_t)expireStartedAt transaction:(YapDatabaseReadWriteTransaction *)transaction

@ -31,7 +31,7 @@ import SessionUtilitiesKit
result.threadID = tsMessage.uniqueThreadId
result.sentTimestamp = tsMessage.timestamp
result.recipient = tsMessage.recipientIds().first
if let thread = tsMessage.thread as? TSGroupThread, thread.usesSharedSenderKeys {
if let thread = tsMessage.thread as? TSGroupThread, thread.isClosedGroup {
let groupID = thread.groupModel.groupId
result.groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID)
}

@ -5,6 +5,7 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
#import <SessionMessagingKit/AppReadiness.h>
#import <SessionMessagingKit/Environment.h>
#import <SessionMessagingKit/GeneralUtilities.h>
#import <SessionMessagingKit/NotificationsProtocol.h>
#import <SessionMessagingKit/NSData+messagePadding.h>
#import <SessionMessagingKit/OWSAudioPlayer.h>
@ -34,7 +35,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
#import <SessionMessagingKit/ProtoUtils.h>
#import <SessionMessagingKit/SignalRecipient.h>
#import <SessionMessagingKit/SSKEnvironment.h>
#import <SessionMessagingKit/SSKJobRecord.h>
#import <SessionMessagingKit/TSAccountManager.h>
#import <SessionMessagingKit/TSAttachment.h>
#import <SessionMessagingKit/TSAttachmentPointer.h>

@ -241,7 +241,6 @@ extension MessageReceiver {
thread.setGroupModel(group, with: transaction)
} else {
thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction)
thread.usesSharedSenderKeys = true
thread.save(with: transaction)
}
// Add the group to the user's set of public keys to poll for

@ -20,7 +20,6 @@ extension MessageSender {
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
let group = TSGroupModel(title: name, memberIds: [String](members), image: nil, groupId: groupID, groupType: .closedGroup, adminIds: admins)
let thread = TSGroupThread.getOrCreateThread(with: group, transaction: transaction)
thread.usesSharedSenderKeys = true // TODO: We should be able to safely deprecate this
thread.save(with: transaction)
// Send a closed group update message to all members individually
var promises: [Promise<Void>] = []

@ -242,7 +242,7 @@ public final class MessageSender : NSObject {
storage.write(with: { transaction in
MessageSender.handleSuccessfulMessageSend(message, to: destination, using: transaction)
var shouldNotify = (message is VisibleMessage)
if let closedGroupUpdate = message as? ClosedGroupUpdate, case .new = closedGroupUpdate.kind {
if let closedGroupUpdate = message as? ClosedGroupUpdateV2, case .new = closedGroupUpdate.kind {
shouldNotify = true
}
if shouldNotify {
@ -342,10 +342,9 @@ public final class MessageSender : NSObject {
public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, using transaction: Any) {
guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return }
tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0
tsMessage.isOpenGroupMessage = tsMessage.openGroupServerMessageID != 0
var recipients = [ message.recipient! ]
if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point
let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction as! YapDatabaseReadTransaction), thread.usesSharedSenderKeys {
let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction as! YapDatabaseReadTransaction), thread.isClosedGroup {
recipients = thread.groupModel.groupMemberIds
}
recipients.forEach { recipient in

@ -17,7 +17,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId;
@property (nonatomic, strong) TSGroupModel *groupModel;
@property (nonatomic, readonly) BOOL isOpenGroup;
@property (nonatomic) BOOL usesSharedSenderKeys;
@property (nonatomic, readonly) BOOL isClosedGroup;
+ (instancetype)getOrCreateThreadWithGroupModel:(TSGroupModel *)groupModel;
+ (instancetype)getOrCreateThreadWithGroupModel:(TSGroupModel *)groupModel

@ -156,6 +156,11 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific
return true;
}
- (BOOL)isClosedGroup
{
return (self.groupModel.groupType == closedGroup);
}
- (BOOL)isOpenGroup
{
return (self.groupModel.groupType == openGroup);
@ -163,7 +168,7 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific
- (BOOL)isCurrentUserMemberInGroup
{
NSString *userPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
return [self isUserMemberInGroup:userPublicKey];
}

@ -138,7 +138,7 @@ BOOL IsNoteToSelfEnabled(void)
{
if (!IsNoteToSelfEnabled()) { return NO; }
if (![self isKindOfClass:TSContactThread.class]) { return NO; }
return [self.contactIdentifier isEqual:OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey];
return [self.contactIdentifier isEqual:[SNGeneralUtilities getUserPublicKey]];
}
#pragma mark - To be subclassed.

@ -122,7 +122,7 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
- (NSString *)sessionID
{
if ([self.recipientId isEqual:kLocalProfileUniqueId]) {
return OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
return [SNGeneralUtilities getUserPublicKey];
} else {
return self.recipientId;
}

@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SNGeneralUtilities : NSObject
+ (NSString *)getUserPublicKey;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,16 @@
#import <SessionUtilitiesKit/SessionUtilitiesKit.h>
#import "GeneralUtilities.h"
#import "OWSIdentityManager.h"
NS_ASSUME_NONNULL_BEGIN
@implementation SNGeneralUtilities
+ (NSString *)getUserPublicKey
{
return OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey;
}
@end
NS_ASSUME_NONNULL_END

@ -1,57 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
NS_ASSUME_NONNULL_BEGIN
extern NSErrorDomain const SSKJobRecordErrorDomain;
typedef NS_ERROR_ENUM(SSKJobRecordErrorDomain, JobRecordError){
JobRecordError_AssertionError = 100,
JobRecordError_IllegalStateTransition,
};
typedef NS_ENUM(NSUInteger, SSKJobRecordStatus) {
SSKJobRecordStatus_Unknown,
SSKJobRecordStatus_Ready,
SSKJobRecordStatus_Running,
SSKJobRecordStatus_PermanentlyFailed,
SSKJobRecordStatus_Obsolete
};
#pragma mark -
@interface SSKJobRecord : TSYapDatabaseObject
@property (nonatomic) NSUInteger failureCount;
@property (nonatomic) NSString *label;
- (instancetype)initWithLabel:(NSString *)label NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithUniqueId:(NSString *_Nullable)uniqueId NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
@property (readonly, nonatomic) SSKJobRecordStatus status;
@property (nonatomic, readonly) UInt64 sortId;
- (BOOL)saveAsStartedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
error:(NSError **)outError NS_SWIFT_NAME(saveAsStarted(transaction:));
- (void)saveAsPermanentlyFailedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
NS_SWIFT_NAME(saveAsPermanentlyFailed(transaction:));
- (void)saveAsObsoleteWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
NS_SWIFT_NAME(saveAsObsolete(transaction:));
- (BOOL)saveRunningAsReadyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
error:(NSError **)outError NS_SWIFT_NAME(saveRunningAsReady(transaction:));
- (BOOL)addFailureWithWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
error:(NSError **)outError NS_SWIFT_NAME(addFailure(transaction:));
@end
NS_ASSUME_NONNULL_END

@ -1,127 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "SSKJobRecord.h"
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
NSErrorDomain const SSKJobRecordErrorDomain = @"SignalServiceKit.JobRecord";
#pragma mark -
@interface SSKJobRecord ()
@property (nonatomic) SSKJobRecordStatus status;
@property (nonatomic) UInt64 sortId;
@end
@implementation SSKJobRecord
- (instancetype)initWithLabel:(NSString *)label
{
self = [super init];
if (!self) {
return self;
}
_status = SSKJobRecordStatus_Ready;
_label = label;
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
}
#pragma mark - TSYapDatabaseObject Overrides
+ (NSString *)collection
{
// To avoid a plethora of identical JobRecord subclasses, all job records share
// a common collection and JobQueue's distinguish their behavior by the job's
// `label`
return @"JobRecord";
}
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
if (self.sortId == 0) {
self.sortId = [SSKIncrementingIdFinder nextIdWithKey:self.class.collection transaction:transaction];
}
[super saveWithTransaction:transaction];
}
#pragma mark -
- (BOOL)saveAsStartedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError
{
if (self.status != SSKJobRecordStatus_Ready) {
*outError =
[NSError errorWithDomain:SSKJobRecordErrorDomain code:JobRecordError_IllegalStateTransition userInfo:nil];
return NO;
}
self.status = SSKJobRecordStatus_Running;
[self saveWithTransaction:transaction];
return YES;
}
- (void)saveAsPermanentlyFailedWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
self.status = SSKJobRecordStatus_PermanentlyFailed;
[self saveWithTransaction:transaction];
}
- (void)saveAsObsoleteWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
self.status = SSKJobRecordStatus_Obsolete;
[self saveWithTransaction:transaction];
}
- (BOOL)saveRunningAsReadyWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError
{
switch (self.status) {
case SSKJobRecordStatus_Running: {
self.status = SSKJobRecordStatus_Ready;
[self saveWithTransaction:transaction];
return YES;
}
case SSKJobRecordStatus_Ready:
case SSKJobRecordStatus_PermanentlyFailed:
case SSKJobRecordStatus_Obsolete:
case SSKJobRecordStatus_Unknown: {
*outError = [NSError errorWithDomain:SSKJobRecordErrorDomain
code:JobRecordError_IllegalStateTransition
userInfo:nil];
return NO;
}
}
}
- (BOOL)addFailureWithWithTransaction:(YapDatabaseReadWriteTransaction *)transaction error:(NSError **)outError
{
switch (self.status) {
case SSKJobRecordStatus_Running: {
self.failureCount++;
[self saveWithTransaction:transaction];
return YES;
}
case SSKJobRecordStatus_Ready:
case SSKJobRecordStatus_PermanentlyFailed:
case SSKJobRecordStatus_Obsolete:
case SSKJobRecordStatus_Unknown: {
*outError = [NSError errorWithDomain:SSKJobRecordErrorDomain
code:JobRecordError_IllegalStateTransition
userInfo:nil];
return NO;
}
}
}
@end
NS_ASSUME_NONNULL_END

@ -1,108 +0,0 @@
@objc(SSKJobRecordFinder)
public class JobRecordFinder: NSObject, Finder {
public typealias ExtensionType = YapDatabaseSecondaryIndex
public typealias TransactionType = YapDatabaseSecondaryIndexTransaction
public enum JobRecordField: String {
case status, label, sortId
}
public func getNextReady(label: String, transaction: YapDatabaseReadTransaction) -> SSKJobRecord? {
var result: SSKJobRecord?
self.enumerateJobRecords(label: label, status: .ready, transaction: transaction) { jobRecord, stopPointer in
result = jobRecord
stopPointer.pointee = true
}
return result
}
public func allRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction) -> [SSKJobRecord] {
var result: [SSKJobRecord] = []
self.enumerateJobRecords(label: label, status: status, transaction: transaction) { jobRecord, _ in
result.append(jobRecord)
}
return result
}
public func enumerateJobRecords(label: String, status: SSKJobRecordStatus, transaction: YapDatabaseReadTransaction, block: @escaping (SSKJobRecord, UnsafeMutablePointer<ObjCBool>) -> Void) {
let queryFormat = String(format: "WHERE %@ = ? AND %@ = ? ORDER BY %@", JobRecordField.status.rawValue, JobRecordField.label.rawValue, JobRecordField.sortId.rawValue)
let query = YapDatabaseQuery(string: queryFormat, parameters: [status.rawValue, label])
self.ext(transaction: transaction).enumerateKeysAndObjects(matching: query) { _, _, object, stopPointer in
guard let jobRecord = object as? SSKJobRecord else {
owsFailDebug("expecting jobRecord but found: \(object)")
return
}
block(jobRecord, stopPointer)
}
}
public static var dbExtensionName: String {
return "SecondaryIndexJobRecord"
}
@objc
public class func asyncRegisterDatabaseExtensionObjC(storage: OWSStorage) {
asyncRegisterDatabaseExtension(storage: storage)
}
public static var dbExtensionConfig: YapDatabaseSecondaryIndex {
let setup = YapDatabaseSecondaryIndexSetup()
setup.addColumn(JobRecordField.sortId.rawValue, with: .integer)
setup.addColumn(JobRecordField.status.rawValue, with: .integer)
setup.addColumn(JobRecordField.label.rawValue, with: .text)
let block: YapDatabaseSecondaryIndexWithObjectBlock = { transaction, dict, collection, key, object in
guard let jobRecord = object as? SSKJobRecord else {
return
}
dict[JobRecordField.sortId.rawValue] = jobRecord.sortId
dict[JobRecordField.status.rawValue] = jobRecord.status.rawValue
dict[JobRecordField.label.rawValue] = jobRecord.label
}
let handler = YapDatabaseSecondaryIndexHandler.withObjectBlock(block)
let options = YapDatabaseSecondaryIndexOptions()
let whitelist = YapWhitelistBlacklist(whitelist: Set([SSKJobRecord.collection()]))
options.allowedCollections = whitelist
return YapDatabaseSecondaryIndex.init(setup: setup, handler: handler, versionTag: "2", options: options)
}
}
protocol Finder {
associatedtype ExtensionType: YapDatabaseExtension
associatedtype TransactionType: YapDatabaseExtensionTransaction
static var dbExtensionName: String { get }
static var dbExtensionConfig: ExtensionType { get }
func ext(transaction: YapDatabaseReadTransaction) -> TransactionType
static func asyncRegisterDatabaseExtension(storage: OWSStorage)
static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage)
}
extension Finder {
public func ext(transaction: YapDatabaseReadTransaction) -> TransactionType {
return transaction.ext(type(of: self).dbExtensionName) as! TransactionType
}
public static func asyncRegisterDatabaseExtension(storage: OWSStorage) {
storage.asyncRegister(dbExtensionConfig, withName: dbExtensionName)
}
// Only for testing.
public static func testingOnly_ensureDatabaseExtensionRegistered(storage: OWSStorage) {
guard storage.registeredExtension(dbExtensionName) == nil else {
return
}
storage.register(dbExtensionConfig, withName: dbExtensionName)
}
}

@ -55,11 +55,11 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
group.groupModel.groupType == .closedGroup { // Should always be true because we don't get PNs for open groups
senderDisplayName = String(format: NotificationStrings.incomingGroupMessageTitleFormat, senderDisplayName, group.groupModel.groupName ?? MessageStrings.newGroupDefaultTitle)
}
case let closedGroupUpdate as ClosedGroupUpdate:
case let closedGroupUpdate as ClosedGroupUpdateV2:
// TODO: We could consider actually handling the update here. Not sure if there's enough time though, seeing as though
// in some cases we need to send messages (e.g. our sender key) to a number of other users.
switch closedGroupUpdate.kind {
case .new(_, let name, _, _, _, _): snippet = "\(senderDisplayName) added you to \(name)"
case .new(_, let name, _, _, _): snippet = "\(senderDisplayName) added you to \(name)"
default: return self.handleFailure(for: notificationContent)
}
default: return self.handleFailure(for: notificationContent)

@ -36,7 +36,7 @@ public class ContactsMigration : OWSDatabaseMigration {
}
// Closed groups
TSGroupThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSGroupThread, thread.usesSharedSenderKeys else { return }
guard let thread = object as? TSGroupThread, thread.isClosedGroup else { return }
let memberSessionIDs = thread.groupModel.groupMemberIds
memberSessionIDs.forEach { memberSessionID in
guard !contacts.contains(where: { $0.sessionID == memberSessionID }) else { return }

@ -1,303 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
/// JobQueue - A durable work queue
///
/// When work needs to be done, add it to the JobQueue.
/// The JobQueue will persist a JobRecord to be sure that work can be restarted if the app is killed.
///
/// The actual work, is carried out in a DurableOperation which the JobQueue spins off, based on the contents
/// of a JobRecord.
///
/// For a concrete example, take message sending.
/// Add an outgoing message to the MessageSenderJobQueue, which first records a SSKMessageSenderJobRecord.
/// The MessageSenderJobQueue then uses that SSKMessageSenderJobRecord to create a MessageSenderOperation which
/// takes care of the actual business of communicating with the service.
///
/// DurableOperations are retryable - via their `remainingRetries` logic. However, if the operation encounters
/// an error where `error.isRetryable == false`, the operation will fail, regardless of available retries.
public extension Error {
var isRetryable: Bool {
return (self as NSError).isRetryable
}
}
extension SSKJobRecordStatus: CustomStringConvertible {
public var description: String {
switch self {
case .ready:
return "ready"
case .unknown:
return "unknown"
case .running:
return "running"
case .permanentlyFailed:
return "permanentlyFailed"
case .obsolete:
return "obsolete"
}
}
}
public enum JobError: Error {
case assertionFailure(description: String)
case obsolete(description: String)
}
public protocol DurableOperation: class {
associatedtype JobRecordType: SSKJobRecord
associatedtype DurableOperationDelegateType: DurableOperationDelegate
var jobRecord: JobRecordType { get }
var durableOperationDelegate: DurableOperationDelegateType? { get set }
var operation: OWSOperation { get }
var remainingRetries: UInt { get set }
}
public protocol DurableOperationDelegate: class {
associatedtype DurableOperationType: DurableOperation
func durableOperationDidSucceed(_ operation: DurableOperationType, transaction: YapDatabaseReadWriteTransaction)
func durableOperation(_ operation: DurableOperationType, didReportError: Error, transaction: YapDatabaseReadWriteTransaction)
func durableOperation(_ operation: DurableOperationType, didFailWithError error: Error, transaction: YapDatabaseReadWriteTransaction)
}
public protocol JobQueue: DurableOperationDelegate {
typealias DurableOperationDelegateType = Self
typealias JobRecordType = DurableOperationType.JobRecordType
// MARK: Dependencies
var dbConnection: YapDatabaseConnection { get }
var finder: JobRecordFinder { get }
// MARK: Default Implementations
func add(jobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction)
func restartOldJobs()
func workStep()
func defaultSetup()
// MARK: Required
var runningOperations: [DurableOperationType] { get set }
var jobRecordLabel: String { get }
var isSetup: Bool { get set }
func setup()
func didMarkAsReady(oldJobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction)
func operationQueue(jobRecord: JobRecordType) -> OperationQueue
func buildOperation(jobRecord: JobRecordType, transaction: YapDatabaseReadTransaction) throws -> DurableOperationType
/// When `requiresInternet` is true, we immediately run any jobs which are waiting for retry upon detecting Reachability.
///
/// Because `Reachability` isn't 100% reliable, the jobs will be attempted regardless of what we think our current Reachability is.
/// However, because these jobs will likely fail many times in succession, their `retryInterval` could be quite long by the time we
/// are back online.
var requiresInternet: Bool { get }
static var maxRetries: UInt { get }
}
public extension JobQueue {
// MARK: Dependencies
var dbConnection: YapDatabaseConnection {
return SSKEnvironment.shared.primaryStorage.dbReadWriteConnection
}
var finder: JobRecordFinder {
return JobRecordFinder()
}
var reachabilityManager: SSKReachabilityManager {
return SSKEnvironment.shared.reachabilityManager
}
// MARK:
func add(jobRecord: JobRecordType, transaction: YapDatabaseReadWriteTransaction) {
assert(jobRecord.status == .ready)
jobRecord.save(with: transaction)
transaction.addCompletionQueue(DispatchQueue.global()) {
self.startWorkWhenAppIsReady()
}
}
func startWorkWhenAppIsReady() {
guard !CurrentAppContext().isRunningTests else {
DispatchQueue.global().async {
self.workStep()
}
return
}
AppReadiness.runNowOrWhenAppDidBecomeReady {
DispatchQueue.global().async {
self.workStep()
}
}
}
func workStep() {
Logger.debug("")
guard isSetup else {
if !CurrentAppContext().isRunningTests {
owsFailDebug("not setup")
}
return
}
Storage.writeSync { transaction in
guard let nextJob: JobRecordType = self.finder.getNextReady(label: self.jobRecordLabel, transaction: transaction) as? JobRecordType else {
Logger.verbose("nothing left to enqueue")
return
}
do {
try nextJob.saveAsStarted(transaction: transaction)
let operationQueue = self.operationQueue(jobRecord: nextJob)
let durableOperation = try self.buildOperation(jobRecord: nextJob, transaction: transaction)
durableOperation.durableOperationDelegate = self as? Self.DurableOperationType.DurableOperationDelegateType
assert(durableOperation.durableOperationDelegate != nil)
let remainingRetries = self.remainingRetries(durableOperation: durableOperation)
durableOperation.remainingRetries = remainingRetries
self.runningOperations.append(durableOperation)
Logger.debug("adding operation: \(durableOperation) with remainingRetries: \(remainingRetries)")
operationQueue.addOperation(durableOperation.operation)
} catch JobError.assertionFailure(let description) {
owsFailDebug("assertion failure: \(description)")
nextJob.saveAsPermanentlyFailed(transaction: transaction)
} catch JobError.obsolete(let description) {
// TODO is this even worthwhile to have obsolete state? Should we just delete the task outright?
Logger.verbose("marking obsolete task as such. description:\(description)")
nextJob.saveAsObsolete(transaction: transaction)
} catch {
owsFailDebug("unexpected error")
}
DispatchQueue.global().async {
self.workStep()
}
}
}
public func restartOldJobs() {
Storage.writeSync { transaction in
let runningRecords = self.finder.allRecords(label: self.jobRecordLabel, status: .running, transaction: transaction)
Logger.info("marking old `running` JobRecords as ready: \(runningRecords.count)")
for record in runningRecords {
guard let jobRecord = record as? JobRecordType else {
owsFailDebug("unexpectred jobRecord: \(record)")
continue
}
do {
try jobRecord.saveRunningAsReady(transaction: transaction)
self.didMarkAsReady(oldJobRecord: jobRecord, transaction: transaction)
} catch {
owsFailDebug("failed to mark old running records as ready error: \(error)")
jobRecord.saveAsPermanentlyFailed(transaction: transaction)
}
}
}
}
/// Unless you need special handling, your setup method can be as simple as
///
/// func setup() {
/// defaultSetup()
/// }
///
/// So you might ask, why not just rename this method to `setup`? Because
/// `setup` is called from objc, and default implementations from a protocol
/// cannot be marked as @objc.
func defaultSetup() {
guard !isSetup else {
owsFailDebug("already ready already")
return
}
self.restartOldJobs()
if self.requiresInternet {
NotificationCenter.default.addObserver(forName: .reachabilityChanged,
object: self.reachabilityManager.observationContext,
queue: nil) { _ in
if self.reachabilityManager.isReachable {
Logger.verbose("isReachable: true")
self.becameReachable()
} else {
Logger.verbose("isReachable: false")
}
}
}
self.isSetup = true
self.startWorkWhenAppIsReady()
}
func remainingRetries(durableOperation: DurableOperationType) -> UInt {
let maxRetries = type(of: self).maxRetries
let failureCount = durableOperation.jobRecord.failureCount
guard maxRetries > failureCount else {
return 0
}
return maxRetries - failureCount
}
func becameReachable() {
guard requiresInternet else {
owsFailDebug("should only be called if `requiresInternet` is true")
return
}
_ = self.runAnyQueuedRetry()
}
func runAnyQueuedRetry() -> DurableOperationType? {
guard let runningDurableOperation = self.runningOperations.first else {
return nil
}
runningDurableOperation.operation.runAnyQueuedRetry()
return runningDurableOperation
}
// MARK: DurableOperationDelegate
func durableOperationDidSucceed(_ operation: DurableOperationType, transaction: YapDatabaseReadWriteTransaction) {
self.runningOperations = self.runningOperations.filter { $0 !== operation }
operation.jobRecord.remove(with: transaction)
}
func durableOperation(_ operation: DurableOperationType, didReportError: Error, transaction: YapDatabaseReadWriteTransaction) {
do {
try operation.jobRecord.addFailure(transaction: transaction)
} catch {
owsFailDebug("error while addingFailure: \(error)")
operation.jobRecord.saveAsPermanentlyFailed(transaction: transaction)
}
}
func durableOperation(_ operation: DurableOperationType, didFailWithError error: Error, transaction: YapDatabaseReadWriteTransaction) {
self.runningOperations = self.runningOperations.filter { $0 !== operation }
operation.jobRecord.saveAsPermanentlyFailed(transaction: transaction)
}
}
Loading…
Cancel
Save