Further config util logic
Removed the usage of the OWSAES256Key (using CryptoKit and raw data instead) Removed the pre-compiled headers to speed up builds with minor changes (explicit imports instead) # Conflicts: # Session.xcodeproj/project.pbxproj # SessionMessagingKit/Database/Models/ClosedGroup.swift # SessionMessagingKit/Protos/Generated/SNProto.swift # SessionMessagingKit/Protos/Generated/SessionProtos.pb.swift # SessionMessagingKit/Protos/SessionProtos.proto # SessionMessagingKit/Sending & Receiving/MessageSender.swift # SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift # SessionMessagingKit/Utilities/ProfileManager.swift # SessionSnodeKit/Models/DeleteAllMessagesRequest.swift # SessionSnodeKit/Models/GetMessagesRequest.swift # SessionSnodeKit/Models/SendMessageRequest.swift # SessionSnodeKit/Types/SnodeAPINamespace.swift
This commit is contained in:
parent
f12191f85e
commit
1345e89809
|
@ -320,7 +320,6 @@
|
|||
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, ); }; };
|
||||
C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA99255A57FE00E217F9 /* OutageDetection.swift */; };
|
||||
C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; };
|
||||
C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; };
|
||||
C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAC3255A580200E217F9 /* OWSDispatch.m */; };
|
||||
|
@ -524,7 +523,6 @@
|
|||
FD09797927FAB7E800936362 /* ImageFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09797827FAB7E800936362 /* ImageFormat.swift */; };
|
||||
FD09797B27FBB25900936362 /* Updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09797A27FBB25900936362 /* Updatable.swift */; };
|
||||
FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09797C27FBDB2000936362 /* Notification+Utilities.swift */; };
|
||||
FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09797E27FCFBFF00936362 /* OWSAES256Key+Utilities.swift */; };
|
||||
FD09798127FCFEE800936362 /* SessionThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09798027FCFEE800936362 /* SessionThread.swift */; };
|
||||
FD09798327FD1A1500936362 /* ClosedGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09798227FD1A1500936362 /* ClosedGroup.swift */; };
|
||||
FD09798527FD1A6500936362 /* ClosedGroupKeyPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD09798427FD1A6500936362 /* ClosedGroupKeyPair.swift */; };
|
||||
|
@ -786,6 +784,10 @@
|
|||
FD8ECF8629346DA100C0D1BB /* HeaderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C906127E411AF00CD579F /* HeaderSpec.swift */; };
|
||||
FD8ECF8729346DB500C0D1BB /* RequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C906327E4122F00CD579F /* RequestSpec.swift */; };
|
||||
FD8ECF892935AB7200C0D1BB /* SessionUtilError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */; };
|
||||
FD8ECF8B2935DB4B00C0D1BB /* SharedConfigMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF8A2935DB4B00C0D1BB /* SharedConfigMessage.swift */; };
|
||||
FD8ECF9029381FC200C0D1BB /* SessionUtil+UserProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF8F29381FC200C0D1BB /* SessionUtil+UserProfile.swift */; };
|
||||
FD8ECF922938552800C0D1BB /* Threading.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF912938552800C0D1BB /* Threading.swift */; };
|
||||
FD8ECF94293856AF00C0D1BB /* Randomness.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8ECF93293856AF00C0D1BB /* Randomness.swift */; };
|
||||
FD90040F2818AB6D00ABAAF6 /* GetSnodePoolJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */; };
|
||||
FD9004122818ABDC00ABAAF6 /* Job.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73F280402C4004C14C5 /* Job.swift */; };
|
||||
FD9004142818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */; };
|
||||
|
@ -1094,7 +1096,6 @@
|
|||
3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageTimerView.m; sourceTree = "<group>"; };
|
||||
3430FE171F7751D4000EC51B /* GiphyAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyAPI.swift; sourceTree = "<group>"; };
|
||||
34480B371FD092A900BC14EF /* SignalShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SignalShareExtension-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
34480B381FD092E300BC14EF /* SessionShareExtension-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SessionShareExtension-Prefix.pch"; sourceTree = "<group>"; };
|
||||
34661FB720C1C0D60056EDD6 /* message_sent.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; name = message_sent.aiff; path = Session/Meta/AudioFiles/message_sent.aiff; sourceTree = SOURCE_ROOT; };
|
||||
346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CropScaleImageViewController.swift; sourceTree = "<group>"; };
|
||||
3488F9352191CC4000E524CC /* MediaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaView.swift; sourceTree = "<group>"; };
|
||||
|
@ -1410,7 +1411,6 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = "<group>"; };
|
||||
C33FDABE255A580100E217F9 /* TSConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSConstants.m; sourceTree = "<group>"; };
|
||||
|
@ -1564,7 +1564,6 @@
|
|||
C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = "SignalUtilitiesKit/Shared Views/Toast.swift"; sourceTree = SOURCE_ROOT; };
|
||||
C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = "SignalUtilitiesKit/Shared Views/TappableStackView.swift"; sourceTree = SOURCE_ROOT; };
|
||||
C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SessionUIKit/Components/GradientView.swift; sourceTree = SOURCE_ROOT; };
|
||||
C38EF458255B710A007E1867 /* SignalUtilitiesKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalUtilitiesKit-Prefix.pch"; sourceTree = "<group>"; };
|
||||
C396469C2509D3ED00B0B9F5 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C396469D2509D3F400B0B9F5 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
C396469E2509D40400B0B9F5 /* vi-VN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "vi-VN"; path = "vi-VN.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
|
@ -1646,7 +1645,6 @@
|
|||
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 /* Session-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Session-Info.plist"; 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; };
|
||||
|
@ -1674,7 +1672,6 @@
|
|||
FD09797827FAB7E800936362 /* ImageFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageFormat.swift; sourceTree = "<group>"; };
|
||||
FD09797A27FBB25900936362 /* Updatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updatable.swift; sourceTree = "<group>"; };
|
||||
FD09797C27FBDB2000936362 /* Notification+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FD09797E27FCFBFF00936362 /* OWSAES256Key+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OWSAES256Key+Utilities.swift"; sourceTree = "<group>"; };
|
||||
FD09798027FCFEE800936362 /* SessionThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionThread.swift; sourceTree = "<group>"; };
|
||||
FD09798227FD1A1500936362 /* ClosedGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosedGroup.swift; sourceTree = "<group>"; };
|
||||
FD09798427FD1A6500936362 /* ClosedGroupKeyPair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosedGroupKeyPair.swift; sourceTree = "<group>"; };
|
||||
|
@ -1907,6 +1904,10 @@
|
|||
FD8ECF812934387A00C0D1BB /* ConfigUserProfileSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigUserProfileSpec.swift; sourceTree = "<group>"; };
|
||||
FD8ECF842934508B00C0D1BB /* BatchResponseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchResponseSpec.swift; sourceTree = "<group>"; };
|
||||
FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionUtilError.swift; sourceTree = "<group>"; };
|
||||
FD8ECF8A2935DB4B00C0D1BB /* SharedConfigMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedConfigMessage.swift; sourceTree = "<group>"; };
|
||||
FD8ECF8F29381FC200C0D1BB /* SessionUtil+UserProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionUtil+UserProfile.swift"; sourceTree = "<group>"; };
|
||||
FD8ECF912938552800C0D1BB /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
||||
FD8ECF93293856AF00C0D1BB /* Randomness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Randomness.swift; sourceTree = "<group>"; };
|
||||
FD90040E2818AB6D00ABAAF6 /* GetSnodePoolJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetSnodePoolJob.swift; sourceTree = "<group>"; };
|
||||
FD9004132818AD0B00ABAAF6 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
|
||||
FDA8EAFD280E8B78002B68E5 /* FailedMessageSendsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedMessageSendsJob.swift; sourceTree = "<group>"; };
|
||||
|
@ -2710,6 +2711,8 @@
|
|||
C3C2A7702553A41E00C340D1 /* ControlMessage.swift */,
|
||||
B8DE1FB526C22FCB0079C9CE /* CallMessage.swift */,
|
||||
C34A977325A3E34A00852C71 /* ClosedGroupControlMessage.swift */,
|
||||
C34A977325A3E34A00852C71 /* LegacyClosedGroupControlMessage.swift */,
|
||||
FD8ECF8A2935DB4B00C0D1BB /* SharedConfigMessage.swift */,
|
||||
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */,
|
||||
7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */,
|
||||
B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */,
|
||||
|
@ -2770,7 +2773,6 @@
|
|||
4535186F1FC635DD00210559 /* Info.plist */,
|
||||
34B0796E1FD07B1E00E248C2 /* SignalShareExtension.entitlements */,
|
||||
34480B371FD092A900BC14EF /* SignalShareExtension-Bridging-Header.h */,
|
||||
34480B381FD092E300BC14EF /* SessionShareExtension-Prefix.pch */,
|
||||
);
|
||||
path = Meta;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2926,7 +2928,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */,
|
||||
C38EF458255B710A007E1867 /* SignalUtilitiesKit-Prefix.pch */,
|
||||
C33FD9AE255A548A00E217F9 /* Info.plist */,
|
||||
);
|
||||
path = Meta;
|
||||
|
@ -3202,7 +3203,6 @@
|
|||
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */,
|
||||
C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */,
|
||||
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
|
||||
FD09797E27FCFBFF00936362 /* OWSAES256Key+Utilities.swift */,
|
||||
C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */,
|
||||
C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */,
|
||||
C38EF281255B6D84007E1867 /* OWSAudioSession.swift */,
|
||||
|
@ -3382,7 +3382,6 @@
|
|||
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */,
|
||||
C33FDA8B255A57FD00E217F9 /* AppVersion.m */,
|
||||
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */,
|
||||
C33FDA99255A57FE00E217F9 /* OutageDetection.swift */,
|
||||
C33FDB80255A581100E217F9 /* Notification+Loki.swift */,
|
||||
C33FDC16255A581E00E217F9 /* FunctionalUtil.h */,
|
||||
C33FDB17255A580800E217F9 /* FunctionalUtil.m */,
|
||||
|
@ -3436,7 +3435,6 @@
|
|||
FDF2220A2818F38D000A4995 /* SessionApp.swift */,
|
||||
45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */,
|
||||
D221A095169C9E5E00537ABF /* Session-Info.plist */,
|
||||
D221A09B169C9E5E00537ABF /* Session-Prefix.pch */,
|
||||
4C63CBFF210A620B003AE45C /* SignalTSan.supp */,
|
||||
4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */,
|
||||
34074F54203D0722004596AE /* Sounds */,
|
||||
|
@ -3568,6 +3566,8 @@
|
|||
FD09797127FAA2F500936362 /* Optional+Utilities.swift */,
|
||||
FD09797C27FBDB2000936362 /* Notification+Utilities.swift */,
|
||||
FDF222082818D2B0000A4995 /* NSAttributedString+Utilities.swift */,
|
||||
FD8ECF912938552800C0D1BB /* Threading.swift */,
|
||||
FD8ECF93293856AF00C0D1BB /* Randomness.swift */,
|
||||
C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */,
|
||||
C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */,
|
||||
);
|
||||
|
@ -4027,9 +4027,10 @@
|
|||
FD8ECF7529340F4800C0D1BB /* LibSessionUtil */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD8ECF8E29381FB200C0D1BB /* Config Handling */,
|
||||
FD8ECF7829340F7100C0D1BB /* libsession-util.xcframework */,
|
||||
FD8ECF7A29340FFD00C0D1BB /* SessionUtil.swift */,
|
||||
FD8ECF882935AB7200C0D1BB /* SessionUtilError.swift */,
|
||||
FD8ECF7A29340FFD00C0D1BB /* SessionUtil.swift */,
|
||||
);
|
||||
path = LibSessionUtil;
|
||||
sourceTree = "<group>";
|
||||
|
@ -4052,6 +4053,14 @@
|
|||
path = Networking;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD8ECF8E29381FB200C0D1BB /* Config Handling */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD8ECF8F29381FC200C0D1BB /* SessionUtil+UserProfile.swift */,
|
||||
);
|
||||
path = "Config Handling";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD9004102818ABB000ABAAF6 /* JobRunner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -5279,7 +5288,6 @@
|
|||
C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */,
|
||||
C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */,
|
||||
C38EF3FB255B6DF7007E1867 /* UIAlertController+OWS.swift in Sources */,
|
||||
C33FDC53255A582000E217F9 /* OutageDetection.swift in Sources */,
|
||||
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */,
|
||||
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */,
|
||||
C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */,
|
||||
|
@ -5437,6 +5445,7 @@
|
|||
FD17D7BA27F51F2100122BE0 /* TargetMigrations.swift in Sources */,
|
||||
FD17D7C327F5204C00122BE0 /* Database+Utilities.swift in Sources */,
|
||||
FD17D7C527F5206300122BE0 /* ColumnDefinition+Utilities.swift in Sources */,
|
||||
FD8ECF94293856AF00C0D1BB /* Randomness.swift in Sources */,
|
||||
FDC438CD27BC641200C60D73 /* Set+Utilities.swift in Sources */,
|
||||
FD77289E284EF1C50018502F /* Sodium+Utilities.swift in Sources */,
|
||||
B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */,
|
||||
|
@ -5458,6 +5467,7 @@
|
|||
FD5D201E27B0D87C00FEA984 /* SessionId.swift in Sources */,
|
||||
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */,
|
||||
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */,
|
||||
FD8ECF922938552800C0D1BB /* Threading.swift in Sources */,
|
||||
B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */,
|
||||
FDF22211281B5E0B000A4995 /* TableRecord+Utilities.swift in Sources */,
|
||||
B88FA7FB26114EA70049422F /* Hex.swift in Sources */,
|
||||
|
@ -5534,6 +5544,8 @@
|
|||
FD245C6A2850666F00B966DD /* FileServerAPI.swift in Sources */,
|
||||
FDC4386927B4E6B800C60D73 /* String+Utlities.swift in Sources */,
|
||||
FD716E6628502EE200C96BF4 /* CurrentCallProtocol.swift in Sources */,
|
||||
FD26FA512919F9CE005801D8 /* GroupDeleteMessage.swift in Sources */,
|
||||
FD8ECF9029381FC200C0D1BB /* SessionUtil+UserProfile.swift in Sources */,
|
||||
FD09B7E5288670BB00ED0B66 /* _008_EmojiReacts.swift in Sources */,
|
||||
FDC4385F27B4C4A200C60D73 /* PinnedMessage.swift in Sources */,
|
||||
7BFD1A8C2747150E00FB91B9 /* TurnServerInfo.swift in Sources */,
|
||||
|
@ -5550,10 +5562,10 @@
|
|||
FDC4386727B4E10E00C60D73 /* Capabilities.swift in Sources */,
|
||||
FDC438A427BB107F00C60D73 /* UserBanRequest.swift in Sources */,
|
||||
C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */,
|
||||
FD09797F27FCFBFF00936362 /* OWSAES256Key+Utilities.swift in Sources */,
|
||||
FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */,
|
||||
FD09798327FD1A1500936362 /* ClosedGroup.swift in Sources */,
|
||||
B8B320B7258C30D70020074B /* HTMLMetadata.swift in Sources */,
|
||||
FD8ECF8B2935DB4B00C0D1BB /* SharedConfigMessage.swift in Sources */,
|
||||
FD09798727FD1B7800936362 /* GroupMember.swift in Sources */,
|
||||
FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */,
|
||||
FD3E0C84283B5835002A425C /* SessionThreadViewModel.swift in Sources */,
|
||||
|
@ -6153,7 +6165,6 @@
|
|||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SessionShareExtension-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"COCOAPODS=1",
|
||||
|
@ -6227,7 +6238,6 @@
|
|||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "SessionShareExtension/Meta/SessionShareExtension-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"COCOAPODS=1",
|
||||
|
@ -6569,7 +6579,6 @@
|
|||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREFIX_HEADER = "SignalUtilitiesKit/Meta/SignalUtilitiesKit-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"COCOAPODS=1",
|
||||
|
@ -6651,7 +6660,6 @@
|
|||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREFIX_HEADER = "SignalUtilitiesKit/Meta/SignalUtilitiesKit-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"COCOAPODS=1",
|
||||
|
@ -7296,7 +7304,6 @@
|
|||
);
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Session/Meta/Session-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
|
@ -7368,7 +7375,6 @@
|
|||
);
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Session/Meta/Session-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
HAVE_CONFIG_H,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
import Foundation
|
||||
import CallKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
extension SessionCallManager: CXProviderDelegate {
|
||||
public func providerDidReset(_ provider: CXProvider) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
|||
import CallKit
|
||||
import GRDB
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
public final class SessionCallManager: NSObject, CallManagerProtocol {
|
||||
let provider: CXProvider?
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import WebRTC
|
||||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
// Note: 'RTCMTLVideoView' doesn't seem to work on the simulator so use 'RTCEAGLVideoView' instead
|
||||
|
@ -27,7 +29,7 @@ class RemoteVideoView: TargetView {
|
|||
return
|
||||
}
|
||||
|
||||
DispatchMainThreadSafe {
|
||||
Threading.dispatchMainThreadSafe {
|
||||
let frameRatio = Double(frame.height) / Double(frame.width)
|
||||
let frameRotation = frame.rotation
|
||||
let deviceRotation = UIDevice.current.orientation
|
||||
|
@ -93,7 +95,8 @@ class LocalVideoView: TargetView {
|
|||
|
||||
override func renderFrame(_ frame: RTCVideoFrame?) {
|
||||
super.renderFrame(frame)
|
||||
DispatchMainThreadSafe {
|
||||
|
||||
Threading.dispatchMainThreadSafe {
|
||||
// This is a workaround for a weird issue that
|
||||
// sometimes the rotationOverride is not working
|
||||
// if it is only set once on initialization
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import UIKit
|
||||
import GRDB
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class StyledSearchController: UISearchController {
|
||||
public override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
|
|
|
@ -4,7 +4,6 @@ import UIKit
|
|||
import CoreServices
|
||||
import Photos
|
||||
import PhotosUI
|
||||
import Sodium
|
||||
import PromiseKit
|
||||
import GRDB
|
||||
import SessionMessagingKit
|
||||
|
@ -1799,7 +1798,7 @@ extension ConversationVC:
|
|||
message: unsendRequest,
|
||||
threadId: threadId,
|
||||
interactionId: nil,
|
||||
to: .contact(publicKey: userPublicKey)
|
||||
to: .contact(publicKey: userPublicKey, namespace: .default)
|
||||
)
|
||||
}
|
||||
return
|
||||
|
@ -1818,7 +1817,7 @@ extension ConversationVC:
|
|||
message: unsendRequest,
|
||||
threadId: threadId,
|
||||
interactionId: nil,
|
||||
to: .contact(publicKey: userPublicKey)
|
||||
to: .contact(publicKey: userPublicKey, namespace: .default)
|
||||
)
|
||||
}
|
||||
self?.showInputAccessoryView()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import UIKit
|
||||
import SessionUIKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
protocol EmojiPickerCollectionViewDelegate: AnyObject {
|
||||
func emojiPicker(_ emojiPicker: EmojiPickerCollectionView?, didSelectEmoji emoji: EmojiWithSkinTones)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import UIKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
|
||||
class EmojiSkinTonePicker: UIView {
|
||||
let emoji: Emoji
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import UIKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
protocol LinkPreviewState {
|
||||
var isLoaded: Bool { get }
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import UIKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class MediaAlbumView: UIStackView {
|
||||
private let items: [Attachment]
|
||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
|||
import YYImage
|
||||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class MediaView: UIView {
|
||||
static let contentMode: UIView.ContentMode = .scaleAspectFill
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import UIKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
|
||||
@objc class TypingIndicatorView: UIStackView {
|
||||
// This represents the spacing between the dots
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#import "OWSMath.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SessionUtilitiesKit/NSTimer+Proxying.h>
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
extension Emoji {
|
||||
private static let availableCache: Atomic<[Emoji:Bool]> = Atomic([:])
|
||||
|
|
|
@ -5,6 +5,7 @@ import PureLayout
|
|||
import SessionUIKit
|
||||
import SessionUtilitiesKit
|
||||
import NVActivityIndicatorView
|
||||
import SignalCoreKit
|
||||
|
||||
class EmptySearchResultCell: UITableViewCell {
|
||||
private lazy var messageLabel: UILabel = {
|
||||
|
|
|
@ -7,6 +7,7 @@ import SessionUIKit
|
|||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSource {
|
||||
fileprivate typealias SectionModel = ArraySection<SearchSection, SessionThreadViewModel>
|
||||
|
|
|
@ -6,6 +6,7 @@ import GRDB
|
|||
import DifferenceKit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class AllMediaViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
||||
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MediaPlayer
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
// This kind of view is tricky. I've tried to organize things in the
|
||||
// simplest possible way.
|
||||
|
|
|
@ -6,6 +6,7 @@ import GRDB
|
|||
import DifferenceKit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class DocumentTileViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import PromiseKit
|
|||
import SignalUtilitiesKit
|
||||
import SignalUtilitiesKit
|
||||
import YYImage
|
||||
import SignalCoreKit
|
||||
|
||||
class GifPickerCell: UICollectionViewCell {
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
protocol GifPickerLayoutDelegate: AnyObject {
|
||||
func imageInfosForLayout() -> [GiphyImageInfo]
|
||||
|
|
|
@ -7,6 +7,7 @@ import Reachability
|
|||
import SignalUtilitiesKit
|
||||
import PromiseKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
|
||||
class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegate, GifPickerLayoutDelegate {
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import AFNetworking
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
import CoreServices
|
||||
import SignalCoreKit
|
||||
|
||||
// There's no UTI type for webp!
|
||||
enum GiphyFormat {
|
||||
|
|
|
@ -7,6 +7,7 @@ import Photos
|
|||
import PromiseKit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
protocol ImagePickerGridControllerDelegate: AnyObject {
|
||||
func imagePickerDidCompleteSelection(_ imagePicker: ImagePickerGridController)
|
||||
|
|
|
@ -5,6 +5,7 @@ import YYImage
|
|||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
public enum MediaGalleryOption {
|
||||
case sliderEnabled
|
||||
|
|
|
@ -6,6 +6,7 @@ import PromiseKit
|
|||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, MediaDetailViewControllerDelegate, InteractivelyDismissableViewController {
|
||||
class DynamicallySizedView: UIView {
|
||||
|
|
|
@ -6,6 +6,7 @@ import GRDB
|
|||
import DifferenceKit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class MediaTileViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import PromiseKit
|
||||
import CoreServices
|
||||
import SignalCoreKit
|
||||
|
||||
protocol PhotoCaptureDelegate: AnyObject {
|
||||
func photoCapture(_ photoCapture: PhotoCapture, didFinishProcessingAttachment attachment: SignalAttachment)
|
||||
|
|
|
@ -5,6 +5,7 @@ import AVFoundation
|
|||
import PromiseKit
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
protocol PhotoCaptureViewControllerDelegate: AnyObject {
|
||||
func photoCaptureViewController(_ photoCaptureViewController: PhotoCaptureViewController, didFinishProcessingAttachment attachment: SignalAttachment)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import UIKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
|
||||
public enum PhotoGridItemType {
|
||||
case photo, animated, video
|
||||
|
|
|
@ -6,6 +6,8 @@ import Foundation
|
|||
import Photos
|
||||
import PromiseKit
|
||||
import CoreServices
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
protocol PhotoLibraryDelegate: AnyObject {
|
||||
func photoLibraryDidChange(_ photoLibrary: PhotoLibrary)
|
||||
|
@ -53,7 +55,7 @@ class PhotoPickerAssetItem: PhotoGridItem {
|
|||
// Surprisingly, iOS will opportunistically run the completion block sync if the image is
|
||||
// already available.
|
||||
photoCollectionContents.requestThumbnail(for: self.asset, thumbnailSize: photoMediaSize.thumbnailSize) { image, _ in
|
||||
DispatchMainThreadSafe({
|
||||
Threading.dispatchMainThreadSafe {
|
||||
// Once we've _successfully_ completed (e.g. invoked the completion with
|
||||
// a non-nil image), don't invoke the completion again with a nil argument.
|
||||
if !hasLoadedImage || image != nil {
|
||||
|
@ -63,7 +65,7 @@ class PhotoPickerAssetItem: PhotoGridItem {
|
|||
hasLoadedImage = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
|||
import Photos
|
||||
import PromiseKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
class SendMediaNavigationController: UINavigationController {
|
||||
public override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
|
|
|
@ -12,6 +12,7 @@ import SessionUIKit
|
|||
import UserNotifications
|
||||
import UIKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public class AppEnvironment {
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#import "MainAppContext.h"
|
||||
#import "Session-Swift.h"
|
||||
#import <SignalCoreKit/Threading.h>
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -259,7 +259,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
|
|||
{
|
||||
OWSAssertDebug(block);
|
||||
|
||||
DispatchMainThreadSafe(^{
|
||||
[Threading dispatchMainThreadSafe:^{
|
||||
if (self.isMainAppAndActive) {
|
||||
// App active blocks typically will be used to safely access the
|
||||
// shared data container, so use a background task to protect this
|
||||
|
@ -273,7 +273,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
|
|||
}
|
||||
|
||||
[self.appActiveBlocks addObject:block];
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)runAppActiveBlocks
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Availability.h>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <SignalCoreKit/NSObject+OWS.h>
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalUtilitiesKit/SSKAsserts.h>
|
||||
#import <SessionUIKit/SessionUIKit.h>
|
||||
#endif
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
public struct SessionApp {
|
||||
static let homeViewController: Atomic<HomeVC?> = Atomic(nil)
|
||||
|
|
|
@ -16,11 +16,6 @@
|
|||
#import <PureLayout/PureLayout.h>
|
||||
#import <Reachability/Reachability.h>
|
||||
#import <SignalCoreKit/Cryptography.h>
|
||||
#import <SignalCoreKit/NSData+OWS.h>
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/OWSLogs.h>
|
||||
#import <SignalCoreKit/Threading.h>
|
||||
#import <SessionMessagingKit/OWSAudioPlayer.h>
|
||||
#import <SignalUtilitiesKit/OWSFormat.h>
|
||||
#import <SignalUtilitiesKit/OWSViewController.h>
|
||||
|
|
|
@ -5,6 +5,7 @@ import GRDB
|
|||
import PromiseKit
|
||||
import SessionMessagingKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
/// There are two primary components in our system notification integration:
|
||||
///
|
||||
|
|
|
@ -7,6 +7,7 @@ import PromiseKit
|
|||
import PushKit
|
||||
import SignalUtilitiesKit
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
|
||||
public enum PushRegistrationError: Error {
|
||||
case assertionError(description: String)
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public enum SyncPushTokensJob: JobExecutor {
|
||||
public static let maxFailureCount: Int = -1
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UserNotifications
|
||||
import PromiseKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
class UserNotificationConfig {
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import DifferenceKit
|
|||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
class HelpViewModel: SessionTableViewModel<NoNav, HelpViewModel.Section, HelpViewModel.Section> {
|
||||
// MARK: - Section
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "OWSBezierPathView.h"
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
|||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
class ScreenLockUI {
|
||||
public static let shared: ScreenLockUI = ScreenLockUI()
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
import SessionMessagingKit
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import Foundation
|
||||
import SessionUtilitiesKit
|
||||
import UIKit
|
||||
import SignalCoreKit
|
||||
|
||||
@objc public extension UIApplication {
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import Sodium
|
||||
import YapDatabase
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum SMKLegacy {
|
||||
|
@ -89,10 +88,23 @@ public enum SMKLegacy {
|
|||
|
||||
@objc(SNContact)
|
||||
public class _Contact: NSObject, NSCoding {
|
||||
@objc(SNLegacyProfileKey)
|
||||
public class _LegacyProfileKey: NSObject, NSCoding {
|
||||
let keyData: Data
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
keyData = coder.decodeObject(forKey: "keyData") as! Data
|
||||
}
|
||||
|
||||
public func encode(with coder: NSCoder) {
|
||||
fatalError("encode(with:) should never be called for legacy types")
|
||||
}
|
||||
}
|
||||
|
||||
public let sessionID: String
|
||||
public var profilePictureURL: String?
|
||||
public var profilePictureFileName: String?
|
||||
public var profileEncryptionKey: OWSAES256Key?
|
||||
public var profileEncryptionKey: _LegacyProfileKey?
|
||||
public var threadID: String?
|
||||
public var isTrusted = false
|
||||
public var isApproved = false
|
||||
|
@ -112,7 +124,7 @@ public enum SMKLegacy {
|
|||
if let nickname = coder.decodeObject(forKey: "nickname") as! String? { self.nickname = nickname }
|
||||
if let profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String? { self.profilePictureURL = profilePictureURL }
|
||||
if let profilePictureFileName = coder.decodeObject(forKey: "profilePictureFileName") as! String? { self.profilePictureFileName = profilePictureFileName }
|
||||
if let profileEncryptionKey = coder.decodeObject(forKey: "profilePictureEncryptionKey") as! OWSAES256Key? { self.profileEncryptionKey = profileEncryptionKey }
|
||||
if let profileEncryptionKey = coder.decodeObject(forKey: "profilePictureEncryptionKey") as! _LegacyProfileKey? { self.profileEncryptionKey = profileEncryptionKey }
|
||||
if let threadID = coder.decodeObject(forKey: "threadID") as! String? { self.threadID = threadID }
|
||||
|
||||
let isBlockedFlag: Bool = coder.decodeBool(forKey: "isBlocked")
|
||||
|
@ -1627,10 +1639,10 @@ public enum SMKLegacy {
|
|||
self.message = message
|
||||
|
||||
if let destString: String = _MessageSendJob.process(rawDestination, type: "contact") {
|
||||
destination = .contact(publicKey: destString)
|
||||
destination = .contact(publicKey: destString, namespace: .default)
|
||||
}
|
||||
else if let destString: String = _MessageSendJob.process(rawDestination, type: "closedGroup") {
|
||||
destination = .closedGroup(groupPublicKey: destString)
|
||||
destination = .closedGroup(groupPublicKey: destString, namespace: .legacyClosedGroup)
|
||||
}
|
||||
else if _MessageSendJob.process(rawDestination, type: "openGroup") != nil {
|
||||
// We can no longer support sending messages to legacy open groups
|
||||
|
|
|
@ -421,7 +421,7 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
nickname: legacyContact.nickname,
|
||||
profilePictureUrl: legacyContact.profilePictureURL,
|
||||
profilePictureFileName: legacyContact.profilePictureFileName,
|
||||
profileEncryptionKey: legacyContact.profileEncryptionKey
|
||||
profileEncryptionKey: legacyContact.profileEncryptionKey?.keyData
|
||||
).migrationSafeInsert(db)
|
||||
|
||||
/// **Note:** The blow "shouldForce" flags are here to allow us to avoid having to run legacy migrations they
|
||||
|
@ -526,7 +526,7 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
let recipientString: String = {
|
||||
if let destination: Message.Destination = destination {
|
||||
switch destination {
|
||||
case .contact(let publicKey): return publicKey
|
||||
case .contact(let publicKey, _): return publicKey
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -974,7 +974,10 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
.keys
|
||||
.map { $0 })
|
||||
.defaulting(to: []),
|
||||
destination: (threadVariant == .contact ? .contact(publicKey: threadId) : nil),
|
||||
destination: (threadVariant == .contact ?
|
||||
.contact(publicKey: threadId, namespace: .default) :
|
||||
nil
|
||||
),
|
||||
variant: variant,
|
||||
useFallback: false
|
||||
)
|
||||
|
@ -986,7 +989,10 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
.keys
|
||||
.map { $0 })
|
||||
.defaulting(to: []),
|
||||
destination: (threadVariant == .contact ? .contact(publicKey: threadId) : nil),
|
||||
destination: (threadVariant == .contact ?
|
||||
.contact(publicKey: threadId, namespace: .default) :
|
||||
nil
|
||||
),
|
||||
variant: variant,
|
||||
useFallback: true
|
||||
)
|
||||
|
@ -1273,8 +1279,8 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
// Fetch the threadId and interactionId this job should be associated with
|
||||
let threadId: String = {
|
||||
switch legacyJob.destination {
|
||||
case .contact(let publicKey): return publicKey
|
||||
case .closedGroup(let groupPublicKey): return groupPublicKey
|
||||
case .contact(let publicKey, _): return publicKey
|
||||
case .closedGroup(let groupPublicKey, _): return groupPublicKey
|
||||
case .openGroup(let roomToken, let server, _, _, _):
|
||||
return OpenGroup.idFor(roomToken: roomToken, server: server)
|
||||
|
||||
|
@ -1430,7 +1436,7 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
behaviour: .recurring,
|
||||
threadId: threadId,
|
||||
details: SendReadReceiptsJob.Details(
|
||||
destination: .contact(publicKey: threadId),
|
||||
destination: .contact(publicKey: threadId, namespace: .default),
|
||||
timestampMsValues: timestampsMs
|
||||
)
|
||||
)?.migrationSafeInserted(db)
|
||||
|
@ -1856,6 +1862,10 @@ enum _003_YDBToGRDBMigration: Migration {
|
|||
SMKLegacy._MessageRequestResponse.self,
|
||||
forClassName: "SNMessageRequestResponse"
|
||||
)
|
||||
NSKeyedUnarchiver.setClass(
|
||||
SMKLegacy._Contact._LegacyProfileKey.self,
|
||||
forClassName: "OWSAES256Key"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ enum _011_SharedUtilChanges: Migration {
|
|||
for: .userProfile
|
||||
)
|
||||
let confResult: SessionUtil.ConfResult = try SessionUtil.update(
|
||||
conf: userProfileConf,
|
||||
with: Profile.fetchOrCreateCurrentUser(db)
|
||||
profile: Profile.fetchOrCreateCurrentUser(db),
|
||||
in: .custom(conf: Atomic(userProfileConf))
|
||||
)
|
||||
|
||||
if confResult.needsDump {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public struct ClosedGroup: Codable, Identifiable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public struct Profile: Codable, Identifiable, Equatable, Hashable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible, CustomStringConvertible, Differentiable {
|
||||
|
@ -42,7 +41,7 @@ public struct Profile: Codable, Identifiable, Equatable, Hashable, FetchableReco
|
|||
public let profilePictureFileName: String?
|
||||
|
||||
/// The key with which the profile is encrypted.
|
||||
public let profileEncryptionKey: OWSAES256Key?
|
||||
public let profileEncryptionKey: Data?
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
|
@ -52,7 +51,7 @@ public struct Profile: Codable, Identifiable, Equatable, Hashable, FetchableReco
|
|||
nickname: String? = nil,
|
||||
profilePictureUrl: String? = nil,
|
||||
profilePictureFileName: String? = nil,
|
||||
profileEncryptionKey: OWSAES256Key? = nil
|
||||
profileEncryptionKey: Data? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
@ -68,7 +67,7 @@ public struct Profile: Codable, Identifiable, Equatable, Hashable, FetchableReco
|
|||
"""
|
||||
Profile(
|
||||
name: \(name),
|
||||
profileKey: \(profileEncryptionKey?.keyData.description ?? "null"),
|
||||
profileKey: \(profileEncryptionKey?.description ?? "null"),
|
||||
profilePictureUrl: \(profilePictureUrl ?? "null")
|
||||
)
|
||||
"""
|
||||
|
@ -81,7 +80,7 @@ public extension Profile {
|
|||
init(from decoder: Decoder) throws {
|
||||
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
var profileKey: OWSAES256Key?
|
||||
var profileKey: Data?
|
||||
var profilePictureUrl: String?
|
||||
|
||||
// If we have both a `profileKey` and a `profilePicture` then the key MUST be valid
|
||||
|
@ -89,12 +88,7 @@ public extension Profile {
|
|||
let profileKeyData: Data = try? container.decode(Data.self, forKey: .profileEncryptionKey),
|
||||
let profilePictureUrlValue: String = try? container.decode(String.self, forKey: .profilePictureUrl)
|
||||
{
|
||||
guard let validProfileKey: OWSAES256Key = OWSAES256Key(data: profileKeyData) else {
|
||||
owsFailDebug("Failed to make profile key for key data")
|
||||
throw StorageError.decodingFailed
|
||||
}
|
||||
|
||||
profileKey = validProfileKey
|
||||
profileKey = profileKeyData
|
||||
profilePictureUrl = profilePictureUrlValue
|
||||
}
|
||||
|
||||
|
@ -113,10 +107,10 @@ public extension Profile {
|
|||
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(nickname, forKey: .nickname)
|
||||
try container.encode(profilePictureUrl, forKey: .profilePictureUrl)
|
||||
try container.encode(profilePictureFileName, forKey: .profilePictureFileName)
|
||||
try container.encode(profileEncryptionKey?.keyData, forKey: .profileEncryptionKey)
|
||||
try container.encodeIfPresent(nickname, forKey: .nickname)
|
||||
try container.encodeIfPresent(profilePictureUrl, forKey: .profilePictureUrl)
|
||||
try container.encodeIfPresent(profilePictureFileName, forKey: .profilePictureFileName)
|
||||
try container.encodeIfPresent(profileEncryptionKey, forKey: .profileEncryptionKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,17 +120,12 @@ public extension Profile {
|
|||
static func fromProto(_ proto: SNProtoDataMessage, id: String) -> Profile? {
|
||||
guard let profileProto = proto.profile, let displayName = profileProto.displayName else { return nil }
|
||||
|
||||
var profileKey: OWSAES256Key?
|
||||
var profileKey: Data?
|
||||
var profilePictureUrl: String?
|
||||
|
||||
// If we have both a `profileKey` and a `profilePicture` then the key MUST be valid
|
||||
if let profileKeyData: Data = proto.profileKey, profileProto.profilePicture != nil {
|
||||
guard let validProfileKey: OWSAES256Key = OWSAES256Key(data: profileKeyData) else {
|
||||
owsFailDebug("Failed to make profile key for key data")
|
||||
return nil
|
||||
}
|
||||
|
||||
profileKey = validProfileKey
|
||||
profileKey = profileKeyData
|
||||
profilePictureUrl = profileProto.profilePicture
|
||||
}
|
||||
|
||||
|
@ -155,8 +144,8 @@ public extension Profile {
|
|||
let profileProto = SNProtoLokiProfile.builder()
|
||||
profileProto.setDisplayName(name)
|
||||
|
||||
if let profileKey: OWSAES256Key = profileEncryptionKey, let profilePictureUrl: String = profilePictureUrl {
|
||||
dataMessageProto.setProfileKey(profileKey.keyData)
|
||||
if let profileKey: Data = profileEncryptionKey, let profilePictureUrl: String = profilePictureUrl {
|
||||
dataMessageProto.setProfileKey(profileKey)
|
||||
profileProto.setProfilePicture(profilePictureUrl)
|
||||
}
|
||||
|
||||
|
@ -178,7 +167,7 @@ public extension Profile {
|
|||
name: String? = nil,
|
||||
profilePictureUrl: Updatable<String?> = .existing,
|
||||
profilePictureFileName: Updatable<String?> = .existing,
|
||||
profileEncryptionKey: Updatable<OWSAES256Key> = .existing
|
||||
profileEncryptionKey: Updatable<Data?> = .existing
|
||||
) -> Profile {
|
||||
return Profile(
|
||||
id: id,
|
||||
|
|
|
@ -4,7 +4,7 @@ import Foundation
|
|||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
||||
internal struct ConfigDump: Codable, Equatable, Hashable, Identifiable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
public struct ConfigDump: Codable, Equatable, Hashable, Identifiable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
|
||||
public static var databaseTableName: String { "configDump" }
|
||||
|
||||
public typealias Columns = CodingKeys
|
||||
|
@ -13,11 +13,11 @@ internal struct ConfigDump: Codable, Equatable, Hashable, Identifiable, Fetchabl
|
|||
case data
|
||||
}
|
||||
|
||||
enum Variant: String, Codable, DatabaseValueConvertible, CaseIterable {
|
||||
public enum Variant: String, Codable, DatabaseValueConvertible, CaseIterable {
|
||||
case userProfile
|
||||
}
|
||||
|
||||
var id: Variant { variant }
|
||||
public var id: Variant { variant }
|
||||
|
||||
/// The type of config this dump is for
|
||||
public let variant: Variant
|
||||
|
@ -25,3 +25,13 @@ internal struct ConfigDump: Codable, Equatable, Hashable, Identifiable, Fetchabl
|
|||
/// The data for this dump
|
||||
public let data: Data
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
|
||||
public extension ConfigDump.Variant {
|
||||
var configMessageKind: SharedConfigMessage.Kind {
|
||||
switch self {
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum AttachmentUploadJob: JobExecutor {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
//import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum FailedMessageSendsJob: JobExecutor {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
||||
|
|
|
@ -27,11 +27,19 @@ public enum MessageReceiveJob: JobExecutor {
|
|||
|
||||
var updatedJob: Job = job
|
||||
var leastSevereError: Error?
|
||||
let nonConfigMessages: [Details.MessageInfo] = details.messages
|
||||
.filter { $0.variant != .sharedConfigMessage }
|
||||
let sharedConfigMessages: [SharedConfigMessage] = details.messages
|
||||
.compactMap { $0.message as? SharedConfigMessage }
|
||||
|
||||
Storage.shared.write { db in
|
||||
// Send any SharedConfigMessages to the SessionUtil to handle it
|
||||
try SessionUtil.handleConfigMessages(db, messages: sharedConfigMessages)
|
||||
|
||||
// Handle the remaining messages
|
||||
var remainingMessagesToProcess: [Details.MessageInfo] = []
|
||||
|
||||
for messageInfo in details.messages {
|
||||
for messageInfo in nonConfigMessages {
|
||||
do {
|
||||
try MessageReceiver.handle(
|
||||
db,
|
||||
|
@ -100,6 +108,8 @@ public enum MessageReceiveJob: JobExecutor {
|
|||
|
||||
extension MessageReceiveJob {
|
||||
public struct Details: Codable {
|
||||
typealias SharedConfigInfo = (message: SharedConfigMessage, serializedProtoData: Data)
|
||||
|
||||
public struct MessageInfo: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case message
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
import SessionSnodeKit
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum RetrieveDefaultOpenGroupRoomsJob: JobExecutor {
|
||||
|
|
|
@ -156,7 +156,7 @@ public extension SendReadReceiptsJob {
|
|||
behaviour: .recurring,
|
||||
threadId: threadId,
|
||||
details: Details(
|
||||
destination: .contact(publicKey: threadId),
|
||||
destination: .contact(publicKey: threadId, namespace: .default),
|
||||
timestampMsValues: timestampMsValues.asSet()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum UpdateProfilePictureJob: JobExecutor {
|
||||
|
@ -37,6 +36,7 @@ public enum UpdateProfilePictureJob: JobExecutor {
|
|||
.updateAll(db, Job.Columns.nextRunTimestamp.set(to: 0))
|
||||
}
|
||||
}
|
||||
SNLog("[UpdateProfilePictureJob] Deferred as not enough time has passed since the last update")
|
||||
deferred(job)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SessionUtil
|
||||
import SessionUtilitiesKit
|
||||
|
||||
internal extension SessionUtil {
|
||||
static func handleUserProfileUpdate(
|
||||
_ db: Database,
|
||||
in target: Target,
|
||||
needsDump: Bool,
|
||||
latestConfigUpdateSentTimestamp: TimeInterval
|
||||
) throws {
|
||||
typealias ProfileData = (profileName: String, profilePictureUrl: String?, profilePictureKey: Data?)
|
||||
|
||||
guard needsDump else { return }
|
||||
guard target.conf.wrappedValue != nil else { throw SessionUtilError.nilConfigObject }
|
||||
|
||||
let userPublicKey: String = getUserHexEncodedPublicKey(db)
|
||||
|
||||
// Since we are doing direct memory manipulation we are using an `Atomic` type which has
|
||||
// blocking access in it's `mutate` closure
|
||||
let maybeProfileData: ProfileData? = target.conf.mutate { conf -> ProfileData? in
|
||||
// A profile must have a name so if this is null then it's invalid and can be ignored
|
||||
guard let profileNamePtr: UnsafePointer<CChar> = user_profile_get_name(conf) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let profileName: String = String(cString: profileNamePtr)
|
||||
let profilePic: user_profile_pic = user_profile_get_pic(conf)
|
||||
var profilePictureUrl: String? = nil
|
||||
var profilePictureKey: Data? = nil
|
||||
|
||||
// Make sure the url and key exist before reading the memory
|
||||
if
|
||||
profilePic.keylen > 0,
|
||||
let profilePictureUrlPtr: UnsafePointer<CChar> = profilePic.url,
|
||||
let profilePictureKeyPtr: UnsafePointer<CChar> = profilePic.key
|
||||
{
|
||||
profilePictureUrl = String(cString: profilePictureUrlPtr)
|
||||
profilePictureKey = Data(bytes: profilePictureKeyPtr, count: profilePic.keylen)
|
||||
}
|
||||
|
||||
return (
|
||||
profileName: profileName,
|
||||
profilePictureUrl: profilePictureUrl,
|
||||
profilePictureKey: profilePictureKey
|
||||
)
|
||||
}
|
||||
|
||||
// Only save the data in the database if it's valid
|
||||
guard let profileData: ProfileData = maybeProfileData else { return }
|
||||
|
||||
// Profile (also force-approve the current user in case the account got into a weird state or
|
||||
// restored directly from a migration)
|
||||
try MessageReceiver.updateProfileIfNeeded(
|
||||
db,
|
||||
publicKey: userPublicKey,
|
||||
name: profileData.profileName,
|
||||
profilePictureUrl: profileData.profilePictureUrl,
|
||||
profileKey: profileData.profilePictureKey,
|
||||
sentTimestamp: latestConfigUpdateSentTimestamp
|
||||
)
|
||||
try Contact(id: userPublicKey)
|
||||
.with(
|
||||
isApproved: true,
|
||||
didApproveMe: true
|
||||
)
|
||||
.save(db)
|
||||
}
|
||||
|
||||
@discardableResult static func update(
|
||||
profile: Profile,
|
||||
in target: Target
|
||||
) throws -> ConfResult {
|
||||
guard target.conf.wrappedValue != nil else { throw SessionUtilError.nilConfigObject }
|
||||
|
||||
// Since we are doing direct memory manipulation we are using an `Atomic` type which has
|
||||
// blocking access in it's `mutate` closure
|
||||
return target.conf.mutate { conf in
|
||||
// Update the name
|
||||
user_profile_set_name(conf, profile.name)
|
||||
|
||||
let profilePic: user_profile_pic? = profile.profilePictureUrl?
|
||||
.bytes
|
||||
.map { CChar(bitPattern: $0) }
|
||||
.withUnsafeBufferPointer { profileUrlPtr in
|
||||
let profileKey: [CChar]? = profile.profileEncryptionKey?
|
||||
.bytes
|
||||
.map { CChar(bitPattern: $0) }
|
||||
|
||||
return profileKey?.withUnsafeBufferPointer { profileKeyPtr in
|
||||
user_profile_pic(
|
||||
url: profileUrlPtr.baseAddress,
|
||||
key: profileKeyPtr.baseAddress,
|
||||
keylen: (profileKey?.count ?? 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if let profilePic: user_profile_pic = profilePic {
|
||||
user_profile_set_pic(conf, profilePic)
|
||||
}
|
||||
|
||||
return (
|
||||
needsPush: config_needs_push(conf),
|
||||
needsDump: config_needs_dump(conf)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,20 @@ import SessionUtil
|
|||
import SessionUtilitiesKit
|
||||
|
||||
/*internal*/public enum SessionUtil {
|
||||
typealias ConfResult = (needsPush: Bool, needsDump: Bool)
|
||||
public typealias ConfResult = (needsPush: Bool, needsDump: Bool)
|
||||
public typealias IncomingConfResult = (needsPush: Bool, needsDump: Bool, latestSentTimestamp: TimeInterval)
|
||||
|
||||
enum Target {
|
||||
case global(variant: ConfigDump.Variant)
|
||||
case custom(conf: Atomic<UnsafeMutablePointer<config_object>?>)
|
||||
|
||||
var conf: Atomic<UnsafeMutablePointer<config_object>?> {
|
||||
switch self {
|
||||
case .global(let variant): return SessionUtil.config(for: variant)
|
||||
case .custom(let conf): return conf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Configs
|
||||
|
||||
|
@ -23,6 +36,13 @@ import SessionUtilitiesKit
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
private static func config(for variant: ConfigDump.Variant) -> Atomic<UnsafeMutablePointer<config_object>?> {
|
||||
switch variant {
|
||||
case .userProfile: return SessionUtil.userProfileConfig
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Loading
|
||||
|
||||
/*internal*/public static func loadState() {
|
||||
|
@ -103,42 +123,104 @@ import SessionUtilitiesKit
|
|||
.save(db)
|
||||
}
|
||||
|
||||
// MARK: - UserProfile
|
||||
// MARK: - Pushes
|
||||
|
||||
internal static func update(
|
||||
conf: UnsafeMutablePointer<config_object>?,
|
||||
with profile: Profile
|
||||
) throws -> ConfResult {
|
||||
guard conf != nil else { throw SessionUtilError.nilConfigObject }
|
||||
public static func getChanges(
|
||||
for variants: [ConfigDump.Variant] = ConfigDump.Variant.allCases
|
||||
) -> [SharedConfigMessage] {
|
||||
return variants
|
||||
.compactMap { variant -> SharedConfigMessage? in
|
||||
let conf = SessionUtil.config(for: variant)
|
||||
|
||||
// Check if the config needs to be pushed
|
||||
guard config_needs_push(conf.wrappedValue) else { return nil }
|
||||
|
||||
var toPush: UnsafeMutablePointer<CChar>? = nil
|
||||
var toPushLen: Int = 0
|
||||
let seqNo: Int64 = conf.mutate { config_push($0, &toPush, &toPushLen) }
|
||||
|
||||
guard let toPush: UnsafeMutablePointer<CChar> = toPush else { return nil }
|
||||
|
||||
let pushData: Data = Data(bytes: toPush, count: toPushLen)
|
||||
toPush.deallocate()
|
||||
|
||||
return SharedConfigMessage(
|
||||
kind: variant.configMessageKind,
|
||||
seqNo: seqNo,
|
||||
data: pushData
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public static func markAsPushed(messages: [SharedConfigMessage]) -> [ConfigDump.Variant: Bool] {
|
||||
messages.reduce(into: [:]) { result, message in
|
||||
let conf = SessionUtil.config(for: message.kind.configDumpVariant)
|
||||
|
||||
// Mark the config as pushed
|
||||
config_confirm_pushed(conf.wrappedValue, message.seqNo)
|
||||
|
||||
// Update the result to indicate whether the config needs to be dumped
|
||||
result[message.kind.configDumpVariant] = config_needs_dump(conf.wrappedValue)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Receiving
|
||||
|
||||
public static func handleConfigMessages(
|
||||
_ db: Database,
|
||||
messages: [SharedConfigMessage]
|
||||
) throws {
|
||||
let groupedMessages: [SharedConfigMessage.Kind: [SharedConfigMessage]] = messages
|
||||
.grouped(by: \.kind)
|
||||
|
||||
// Update the name
|
||||
user_profile_set_name(conf, profile.name)
|
||||
|
||||
let profilePic: user_profile_pic? = profile.profilePictureUrl?
|
||||
.bytes
|
||||
.map { CChar(bitPattern: $0) }
|
||||
.withUnsafeBufferPointer { profileUrlPtr in
|
||||
let profileKey: [CChar]? = profile.profileEncryptionKey?
|
||||
.keyData
|
||||
.bytes
|
||||
.map { CChar(bitPattern: $0) }
|
||||
// Merge the config messages into the current state
|
||||
let results: [ConfigDump.Variant: IncomingConfResult] = groupedMessages
|
||||
.reduce(into: [:]) { result, next in
|
||||
let atomicConf = SessionUtil.config(for: next.key.configDumpVariant)
|
||||
var needsPush: Bool = false
|
||||
var needsDump: Bool = false
|
||||
let messageSentTimestamp: TimeInterval = TimeInterval(
|
||||
(next.value.compactMap { $0.sentTimestamp }.max() ?? 0) / 1000
|
||||
)
|
||||
|
||||
// Block the config while we are merging
|
||||
atomicConf.mutate { conf in
|
||||
var mergeData: [UnsafePointer<CChar>?] = next.value
|
||||
.map { message -> [CChar] in
|
||||
message.data
|
||||
.bytes
|
||||
.map { CChar(bitPattern: $0) }
|
||||
}
|
||||
.unsafeCopy()
|
||||
var mergeSize: [Int] = messages.map { $0.data.count }
|
||||
config_merge(conf, &mergeData, &mergeSize, messages.count)
|
||||
mergeData.forEach { $0?.deallocate() }
|
||||
|
||||
return profileKey?.withUnsafeBufferPointer { profileKeyPtr in
|
||||
user_profile_pic(
|
||||
url: profileUrlPtr.baseAddress,
|
||||
key: profileKeyPtr.baseAddress,
|
||||
keylen: (profileKey?.count ?? 0)
|
||||
)
|
||||
// Get the state of this variant
|
||||
needsPush = config_needs_push(conf)
|
||||
needsDump = config_needs_dump(conf)
|
||||
}
|
||||
|
||||
// Return the current state of the config
|
||||
result[next.key.configDumpVariant] = (
|
||||
needsPush: needsPush,
|
||||
needsDump: needsDump,
|
||||
latestSentTimestamp: messageSentTimestamp
|
||||
)
|
||||
}
|
||||
|
||||
if let profilePic: user_profile_pic = profilePic {
|
||||
user_profile_set_pic(conf, profilePic)
|
||||
// If the data needs to be dumped then apply the relevant local changes
|
||||
try results.forEach { variant, result in
|
||||
switch variant {
|
||||
case .userProfile:
|
||||
try SessionUtil.handleUserProfileUpdate(
|
||||
db,
|
||||
in: .global(variant: variant),
|
||||
needsDump: result.needsDump,
|
||||
latestConfigUpdateSentTimestamp: result.latestSentTimestamp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
needsPush: config_needs_push(conf),
|
||||
needsDump: config_needs_dump(conf)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public final class ClosedGroupControlMessage: ControlMessage {
|
||||
|
|
|
@ -9,7 +9,7 @@ extension ConfigurationMessage {
|
|||
let currentUserProfile: Profile = Profile.fetchOrCreateCurrentUser(db)
|
||||
let displayName: String = currentUserProfile.name
|
||||
let profilePictureUrl: String? = currentUserProfile.profilePictureUrl
|
||||
let profileKey: Data? = currentUserProfile.profileEncryptionKey?.keyData
|
||||
let profileKey: Data? = currentUserProfile.profileEncryptionKey
|
||||
let closedGroups: Set<CMClosedGroup> = try ClosedGroup.fetchAll(db)
|
||||
.compactMap { closedGroup -> CMClosedGroup? in
|
||||
guard let latestKeyPair: ClosedGroupKeyPair = try closedGroup.fetchLatestKeyPair(db) else {
|
||||
|
@ -62,7 +62,7 @@ extension ConfigurationMessage {
|
|||
publicKey: contact.id,
|
||||
displayName: (profile?.name ?? contact.id),
|
||||
profilePictureUrl: profile?.profilePictureUrl,
|
||||
profileKey: profile?.profileEncryptionKey?.keyData,
|
||||
profileKey: profile?.profileEncryptionKey,
|
||||
hasIsApproved: true,
|
||||
isApproved: contact.isApproved,
|
||||
hasIsBlocked: true,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Sodium
|
||||
import GRDB
|
||||
import Curve25519Kit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public final class ConfigurationMessage: ControlMessage {
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public final class SharedConfigMessage: ControlMessage {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case kind
|
||||
case seqNo
|
||||
case data
|
||||
}
|
||||
|
||||
public var kind: Kind
|
||||
public var seqNo: Int64
|
||||
public var data: Data
|
||||
|
||||
public override var isSelfSendValid: Bool { true }
|
||||
|
||||
// MARK: - Kind
|
||||
|
||||
public enum Kind: CustomStringConvertible, Codable {
|
||||
case userProfile
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
case .userProfile: return "userProfile"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
public init(
|
||||
kind: Kind,
|
||||
seqNo: Int64,
|
||||
data: Data
|
||||
) {
|
||||
self.kind = kind
|
||||
self.seqNo = seqNo
|
||||
self.data = data
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Codable
|
||||
|
||||
required init(from decoder: Decoder) throws {
|
||||
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
kind = try container.decode(Kind.self, forKey: .kind)
|
||||
seqNo = try container.decode(Int64.self, forKey: .seqNo)
|
||||
data = try container.decode(Data.self, forKey: .data)
|
||||
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
|
||||
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(kind, forKey: .kind)
|
||||
try container.encode(seqNo, forKey: .seqNo)
|
||||
try container.encode(data, forKey: .data)
|
||||
}
|
||||
|
||||
// MARK: - Proto Conversion
|
||||
|
||||
public override class func fromProto(_ proto: SNProtoContent, sender: String) -> SharedConfigMessage? {
|
||||
guard let sharedConfigMessage = proto.sharedConfigMessage else { return nil }
|
||||
|
||||
return SharedConfigMessage(
|
||||
kind: {
|
||||
switch sharedConfigMessage.kind {
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}(),
|
||||
seqNo: sharedConfigMessage.seqno,
|
||||
data: sharedConfigMessage.data
|
||||
)
|
||||
}
|
||||
|
||||
public override func toProto(_ db: Database) -> SNProtoContent? {
|
||||
do {
|
||||
let sharedConfigMessage: SNProtoSharedConfigMessage.SNProtoSharedConfigMessageBuilder = SNProtoSharedConfigMessage.builder(
|
||||
kind: {
|
||||
switch self.kind {
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}(),
|
||||
seqno: self.seqNo,
|
||||
data: self.data
|
||||
)
|
||||
|
||||
let contentProto = SNProtoContent.builder()
|
||||
contentProto.setSharedConfigMessage(try sharedConfigMessage.build())
|
||||
return try contentProto.build()
|
||||
} catch {
|
||||
SNLog("Couldn't construct data extraction notification proto from: \(self).")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Description
|
||||
|
||||
public var description: String {
|
||||
"""
|
||||
SharedConfigMessage(
|
||||
kind: \(kind.description),
|
||||
seqNo: \(seqNo),
|
||||
data: \(data.count) bytes
|
||||
)
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Convenience
|
||||
|
||||
public extension SharedConfigMessage.Kind {
|
||||
var configDumpVariant: ConfigDump.Variant {
|
||||
switch self {
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,12 +2,19 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public extension Message {
|
||||
enum Destination: Codable {
|
||||
case contact(publicKey: String)
|
||||
case closedGroup(groupPublicKey: String)
|
||||
case contact(
|
||||
publicKey: String,
|
||||
namespace: SnodeAPI.Namespace
|
||||
)
|
||||
case closedGroup(
|
||||
groupPublicKey: String,
|
||||
namespace: SnodeAPI.Namespace
|
||||
)
|
||||
case openGroup(
|
||||
roomToken: String,
|
||||
server: String,
|
||||
|
@ -36,10 +43,10 @@ public extension Message {
|
|||
)
|
||||
}
|
||||
|
||||
return .contact(publicKey: thread.id)
|
||||
return .contact(publicKey: thread.id, namespace: .default)
|
||||
|
||||
case .closedGroup:
|
||||
return .closedGroup(groupPublicKey: thread.id)
|
||||
return .closedGroup(groupPublicKey: thread.id, namespace: .legacyClosedGroup)
|
||||
|
||||
case .openGroup:
|
||||
guard let openGroup: OpenGroup = try thread.openGroup.fetchOne(db) else {
|
||||
|
@ -65,5 +72,59 @@ public extension Message {
|
|||
default: return self
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Codable
|
||||
|
||||
// FIXME: Remove this custom implementation after enough time has passed (added the 'namespace' properties)
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Should only have a single root key so we can just switch on it to have cleaner code
|
||||
switch container.allKeys.first {
|
||||
case .contact:
|
||||
let childContainer: KeyedDecodingContainer<ContactCodingKeys> = try container.nestedContainer(keyedBy: ContactCodingKeys.self, forKey: .contact)
|
||||
|
||||
self = .contact(
|
||||
publicKey: try childContainer.decode(String.self, forKey: .publicKey),
|
||||
namespace: (
|
||||
(try? childContainer.decode(SnodeAPI.Namespace.self, forKey: .namespace)) ??
|
||||
.default
|
||||
)
|
||||
)
|
||||
|
||||
case .closedGroup:
|
||||
let childContainer: KeyedDecodingContainer<ClosedGroupCodingKeys> = try container.nestedContainer(keyedBy: ClosedGroupCodingKeys.self, forKey: .closedGroup)
|
||||
|
||||
self = .closedGroup(
|
||||
groupPublicKey: try childContainer.decode(String.self, forKey: .groupPublicKey),
|
||||
namespace: (
|
||||
(try? childContainer.decode(SnodeAPI.Namespace.self, forKey: .namespace)) ??
|
||||
.legacyClosedGroup
|
||||
)
|
||||
)
|
||||
|
||||
case .openGroup:
|
||||
let childContainer: KeyedDecodingContainer<OpenGroupCodingKeys> = try container.nestedContainer(keyedBy: OpenGroupCodingKeys.self, forKey: .openGroup)
|
||||
|
||||
self = .openGroup(
|
||||
roomToken: try childContainer.decode(String.self, forKey: .roomToken),
|
||||
server: try childContainer.decode(String.self, forKey: .server),
|
||||
whisperTo: try? childContainer.decode(String.self, forKey: .whisperTo),
|
||||
whisperMods: try childContainer.decode(Bool.self, forKey: .whisperMods),
|
||||
fileIds: try? childContainer.decode([String].self, forKey: .fileIds)
|
||||
)
|
||||
|
||||
case .openGroupInbox:
|
||||
let childContainer: KeyedDecodingContainer<OpenGroupInboxCodingKeys> = try container.nestedContainer(keyedBy: OpenGroupInboxCodingKeys.self, forKey: .openGroupInbox)
|
||||
|
||||
self = .openGroupInbox(
|
||||
server: try childContainer.decode(String.self, forKey: .server),
|
||||
openGroupPublicKey: try childContainer.decode(String.self, forKey: .openGroupPublicKey),
|
||||
blindedPublicKey: try childContainer.decode(String.self, forKey: .blindedPublicKey)
|
||||
)
|
||||
|
||||
default: throw MessageReceiverError.invalidMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ public extension Message {
|
|||
case messageRequestResponse
|
||||
case visibleMessage
|
||||
case callMessage
|
||||
case sharedConfigMessage
|
||||
|
||||
init?(from type: Message) {
|
||||
switch type {
|
||||
|
@ -112,6 +113,7 @@ public extension Message {
|
|||
case is MessageRequestResponse: self = .messageRequestResponse
|
||||
case is VisibleMessage: self = .visibleMessage
|
||||
case is CallMessage: self = .callMessage
|
||||
case is SharedConfigMessage: self = .sharedConfigMessage
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +130,7 @@ public extension Message {
|
|||
case .messageRequestResponse: return MessageRequestResponse.self
|
||||
case .visibleMessage: return VisibleMessage.self
|
||||
case .callMessage: return CallMessage.self
|
||||
case .sharedConfigMessage: return SharedConfigMessage.self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +151,7 @@ public extension Message {
|
|||
case .messageRequestResponse: return try container.decode(MessageRequestResponse.self, forKey: key)
|
||||
case .visibleMessage: return try container.decode(VisibleMessage.self, forKey: key)
|
||||
case .callMessage: return try container.decode(CallMessage.self, forKey: key)
|
||||
case .sharedConfigMessage: return try container.decode(SharedConfigMessage.self, forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +169,8 @@ public extension Message {
|
|||
.unsendRequest,
|
||||
.messageRequestResponse,
|
||||
.visibleMessage,
|
||||
.callMessage
|
||||
.callMessage,
|
||||
.sharedConfigMessage
|
||||
]
|
||||
|
||||
return prioritisedVariants
|
||||
|
|
|
@ -114,7 +114,7 @@ public extension VisibleMessage {
|
|||
extension VisibleMessage.VMProfile {
|
||||
init(profile: Profile) {
|
||||
self.displayName = profile.name
|
||||
self.profileKey = profile.profileEncryptionKey?.keyData
|
||||
self.profileKey = profile.profileEncryptionKey
|
||||
self.profilePictureUrl = profile.profilePictureUrl
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,6 +618,9 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
if let _value = messageRequestResponse {
|
||||
builder.setMessageRequestResponse(_value)
|
||||
}
|
||||
if let _value = sharedConfigMessage {
|
||||
builder.setSharedConfigMessage(_value)
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
|
@ -659,6 +662,10 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
proto.messageRequestResponse = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func setSharedConfigMessage(_ valueParam: SNProtoSharedConfigMessage) {
|
||||
proto.sharedConfigMessage = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SNProtoContent {
|
||||
return try SNProtoContent.parseProto(proto)
|
||||
}
|
||||
|
@ -686,6 +693,8 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
|
||||
@objc public let messageRequestResponse: SNProtoMessageRequestResponse?
|
||||
|
||||
@objc public let sharedConfigMessage: SNProtoSharedConfigMessage?
|
||||
|
||||
private init(proto: SessionProtos_Content,
|
||||
dataMessage: SNProtoDataMessage?,
|
||||
callMessage: SNProtoCallMessage?,
|
||||
|
@ -694,7 +703,8 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
configurationMessage: SNProtoConfigurationMessage?,
|
||||
dataExtractionNotification: SNProtoDataExtractionNotification?,
|
||||
unsendRequest: SNProtoUnsendRequest?,
|
||||
messageRequestResponse: SNProtoMessageRequestResponse?) {
|
||||
messageRequestResponse: SNProtoMessageRequestResponse?,
|
||||
sharedConfigMessage: SNProtoSharedConfigMessage?) {
|
||||
self.proto = proto
|
||||
self.dataMessage = dataMessage
|
||||
self.callMessage = callMessage
|
||||
|
@ -704,6 +714,7 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
self.dataExtractionNotification = dataExtractionNotification
|
||||
self.unsendRequest = unsendRequest
|
||||
self.messageRequestResponse = messageRequestResponse
|
||||
self.sharedConfigMessage = sharedConfigMessage
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -757,6 +768,11 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
messageRequestResponse = try SNProtoMessageRequestResponse.parseProto(proto.messageRequestResponse)
|
||||
}
|
||||
|
||||
var sharedConfigMessage: SNProtoSharedConfigMessage? = nil
|
||||
if proto.hasSharedConfigMessage {
|
||||
sharedConfigMessage = try SNProtoSharedConfigMessage.parseProto(proto.sharedConfigMessage)
|
||||
}
|
||||
|
||||
// MARK: - Begin Validation Logic for SNProtoContent -
|
||||
|
||||
// MARK: - End Validation Logic for SNProtoContent -
|
||||
|
@ -769,7 +785,8 @@ extension SNProtoMessageRequestResponse.SNProtoMessageRequestResponseBuilder {
|
|||
configurationMessage: configurationMessage,
|
||||
dataExtractionNotification: dataExtractionNotification,
|
||||
unsendRequest: unsendRequest,
|
||||
messageRequestResponse: messageRequestResponse)
|
||||
messageRequestResponse: messageRequestResponse,
|
||||
sharedConfigMessage: sharedConfigMessage)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -2449,9 +2466,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
builder.setBody(_value)
|
||||
}
|
||||
builder.setAttachments(attachments)
|
||||
if let _value = group {
|
||||
builder.setGroup(_value)
|
||||
}
|
||||
if hasFlags {
|
||||
builder.setFlags(flags)
|
||||
}
|
||||
|
@ -2506,10 +2520,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
proto.attachments = wrappedItems.map { $0.proto }
|
||||
}
|
||||
|
||||
@objc public func setGroup(_ valueParam: SNProtoGroupContext) {
|
||||
proto.group = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func setFlags(_ valueParam: UInt32) {
|
||||
proto.flags = valueParam
|
||||
}
|
||||
|
@ -2573,8 +2583,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
|
||||
@objc public let attachments: [SNProtoAttachmentPointer]
|
||||
|
||||
@objc public let group: SNProtoGroupContext?
|
||||
|
||||
@objc public let quote: SNProtoDataMessageQuote?
|
||||
|
||||
@objc public let preview: [SNProtoDataMessagePreview]
|
||||
|
@ -2640,7 +2648,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
|
||||
private init(proto: SessionProtos_DataMessage,
|
||||
attachments: [SNProtoAttachmentPointer],
|
||||
group: SNProtoGroupContext?,
|
||||
quote: SNProtoDataMessageQuote?,
|
||||
preview: [SNProtoDataMessagePreview],
|
||||
reaction: SNProtoDataMessageReaction?,
|
||||
|
@ -2649,7 +2656,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
closedGroupControlMessage: SNProtoDataMessageClosedGroupControlMessage?) {
|
||||
self.proto = proto
|
||||
self.attachments = attachments
|
||||
self.group = group
|
||||
self.quote = quote
|
||||
self.preview = preview
|
||||
self.reaction = reaction
|
||||
|
@ -2672,11 +2678,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
var attachments: [SNProtoAttachmentPointer] = []
|
||||
attachments = try proto.attachments.map { try SNProtoAttachmentPointer.parseProto($0) }
|
||||
|
||||
var group: SNProtoGroupContext? = nil
|
||||
if proto.hasGroup {
|
||||
group = try SNProtoGroupContext.parseProto(proto.group)
|
||||
}
|
||||
|
||||
var quote: SNProtoDataMessageQuote? = nil
|
||||
if proto.hasQuote {
|
||||
quote = try SNProtoDataMessageQuote.parseProto(proto.quote)
|
||||
|
@ -2711,7 +2712,6 @@ extension SNProtoDataMessageClosedGroupControlMessage.SNProtoDataMessageClosedGr
|
|||
|
||||
let result = SNProtoDataMessage(proto: proto,
|
||||
attachments: attachments,
|
||||
group: group,
|
||||
quote: quote,
|
||||
preview: preview,
|
||||
reaction: reaction,
|
||||
|
@ -3706,152 +3706,91 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
|
||||
#endif
|
||||
|
||||
// MARK: - SNProtoGroupContext
|
||||
// MARK: - SNProtoSharedConfigMessage
|
||||
|
||||
@objc public class SNProtoGroupContext: NSObject {
|
||||
@objc public class SNProtoSharedConfigMessage: NSObject {
|
||||
|
||||
// MARK: - SNProtoGroupContextType
|
||||
// MARK: - SNProtoSharedConfigMessageKind
|
||||
|
||||
@objc public enum SNProtoGroupContextType: Int32 {
|
||||
case unknown = 0
|
||||
case update = 1
|
||||
case deliver = 2
|
||||
case quit = 3
|
||||
case requestInfo = 4
|
||||
@objc public enum SNProtoSharedConfigMessageKind: Int32 {
|
||||
case userProfile = 1
|
||||
}
|
||||
|
||||
private class func SNProtoGroupContextTypeWrap(_ value: SessionProtos_GroupContext.TypeEnum) -> SNProtoGroupContextType {
|
||||
private class func SNProtoSharedConfigMessageKindWrap(_ value: SessionProtos_SharedConfigMessage.Kind) -> SNProtoSharedConfigMessageKind {
|
||||
switch value {
|
||||
case .unknown: return .unknown
|
||||
case .update: return .update
|
||||
case .deliver: return .deliver
|
||||
case .quit: return .quit
|
||||
case .requestInfo: return .requestInfo
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}
|
||||
|
||||
private class func SNProtoGroupContextTypeUnwrap(_ value: SNProtoGroupContextType) -> SessionProtos_GroupContext.TypeEnum {
|
||||
private class func SNProtoSharedConfigMessageKindUnwrap(_ value: SNProtoSharedConfigMessageKind) -> SessionProtos_SharedConfigMessage.Kind {
|
||||
switch value {
|
||||
case .unknown: return .unknown
|
||||
case .update: return .update
|
||||
case .deliver: return .deliver
|
||||
case .quit: return .quit
|
||||
case .requestInfo: return .requestInfo
|
||||
case .userProfile: return .userProfile
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SNProtoGroupContextBuilder
|
||||
// MARK: - SNProtoSharedConfigMessageBuilder
|
||||
|
||||
@objc public class func builder(id: Data, type: SNProtoGroupContextType) -> SNProtoGroupContextBuilder {
|
||||
return SNProtoGroupContextBuilder(id: id, type: type)
|
||||
@objc public class func builder(kind: SNProtoSharedConfigMessageKind, seqno: Int64, data: Data) -> SNProtoSharedConfigMessageBuilder {
|
||||
return SNProtoSharedConfigMessageBuilder(kind: kind, seqno: seqno, data: data)
|
||||
}
|
||||
|
||||
// asBuilder() constructs a builder that reflects the proto's contents.
|
||||
@objc public func asBuilder() -> SNProtoGroupContextBuilder {
|
||||
let builder = SNProtoGroupContextBuilder(id: id, type: type)
|
||||
if let _value = name {
|
||||
builder.setName(_value)
|
||||
}
|
||||
builder.setMembers(members)
|
||||
if let _value = avatar {
|
||||
builder.setAvatar(_value)
|
||||
}
|
||||
builder.setAdmins(admins)
|
||||
@objc public func asBuilder() -> SNProtoSharedConfigMessageBuilder {
|
||||
let builder = SNProtoSharedConfigMessageBuilder(kind: kind, seqno: seqno, data: data)
|
||||
return builder
|
||||
}
|
||||
|
||||
@objc public class SNProtoGroupContextBuilder: NSObject {
|
||||
@objc public class SNProtoSharedConfigMessageBuilder: NSObject {
|
||||
|
||||
private var proto = SessionProtos_GroupContext()
|
||||
private var proto = SessionProtos_SharedConfigMessage()
|
||||
|
||||
@objc fileprivate override init() {}
|
||||
|
||||
@objc fileprivate init(id: Data, type: SNProtoGroupContextType) {
|
||||
@objc fileprivate init(kind: SNProtoSharedConfigMessageKind, seqno: Int64, data: Data) {
|
||||
super.init()
|
||||
|
||||
setId(id)
|
||||
setType(type)
|
||||
setKind(kind)
|
||||
setSeqno(seqno)
|
||||
setData(data)
|
||||
}
|
||||
|
||||
@objc public func setId(_ valueParam: Data) {
|
||||
proto.id = valueParam
|
||||
@objc public func setKind(_ valueParam: SNProtoSharedConfigMessageKind) {
|
||||
proto.kind = SNProtoSharedConfigMessageKindUnwrap(valueParam)
|
||||
}
|
||||
|
||||
@objc public func setType(_ valueParam: SNProtoGroupContextType) {
|
||||
proto.type = SNProtoGroupContextTypeUnwrap(valueParam)
|
||||
@objc public func setSeqno(_ valueParam: Int64) {
|
||||
proto.seqno = valueParam
|
||||
}
|
||||
|
||||
@objc public func setName(_ valueParam: String) {
|
||||
proto.name = valueParam
|
||||
@objc public func setData(_ valueParam: Data) {
|
||||
proto.data = valueParam
|
||||
}
|
||||
|
||||
@objc public func addMembers(_ valueParam: String) {
|
||||
var items = proto.members
|
||||
items.append(valueParam)
|
||||
proto.members = items
|
||||
}
|
||||
|
||||
@objc public func setMembers(_ wrappedItems: [String]) {
|
||||
proto.members = wrappedItems
|
||||
}
|
||||
|
||||
@objc public func setAvatar(_ valueParam: SNProtoAttachmentPointer) {
|
||||
proto.avatar = valueParam.proto
|
||||
}
|
||||
|
||||
@objc public func addAdmins(_ valueParam: String) {
|
||||
var items = proto.admins
|
||||
items.append(valueParam)
|
||||
proto.admins = items
|
||||
}
|
||||
|
||||
@objc public func setAdmins(_ wrappedItems: [String]) {
|
||||
proto.admins = wrappedItems
|
||||
}
|
||||
|
||||
@objc public func build() throws -> SNProtoGroupContext {
|
||||
return try SNProtoGroupContext.parseProto(proto)
|
||||
@objc public func build() throws -> SNProtoSharedConfigMessage {
|
||||
return try SNProtoSharedConfigMessage.parseProto(proto)
|
||||
}
|
||||
|
||||
@objc public func buildSerializedData() throws -> Data {
|
||||
return try SNProtoGroupContext.parseProto(proto).serializedData()
|
||||
return try SNProtoSharedConfigMessage.parseProto(proto).serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate let proto: SessionProtos_GroupContext
|
||||
fileprivate let proto: SessionProtos_SharedConfigMessage
|
||||
|
||||
@objc public let id: Data
|
||||
@objc public let kind: SNProtoSharedConfigMessageKind
|
||||
|
||||
@objc public let type: SNProtoGroupContextType
|
||||
@objc public let seqno: Int64
|
||||
|
||||
@objc public let avatar: SNProtoAttachmentPointer?
|
||||
@objc public let data: Data
|
||||
|
||||
@objc public var name: String? {
|
||||
guard proto.hasName else {
|
||||
return nil
|
||||
}
|
||||
return proto.name
|
||||
}
|
||||
@objc public var hasName: Bool {
|
||||
return proto.hasName
|
||||
}
|
||||
|
||||
@objc public var members: [String] {
|
||||
return proto.members
|
||||
}
|
||||
|
||||
@objc public var admins: [String] {
|
||||
return proto.admins
|
||||
}
|
||||
|
||||
private init(proto: SessionProtos_GroupContext,
|
||||
id: Data,
|
||||
type: SNProtoGroupContextType,
|
||||
avatar: SNProtoAttachmentPointer?) {
|
||||
private init(proto: SessionProtos_SharedConfigMessage,
|
||||
kind: SNProtoSharedConfigMessageKind,
|
||||
seqno: Int64,
|
||||
data: Data) {
|
||||
self.proto = proto
|
||||
self.id = id
|
||||
self.type = type
|
||||
self.avatar = avatar
|
||||
self.kind = kind
|
||||
self.seqno = seqno
|
||||
self.data = data
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -3859,35 +3798,35 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
return try self.proto.serializedData()
|
||||
}
|
||||
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SNProtoGroupContext {
|
||||
let proto = try SessionProtos_GroupContext(serializedData: serializedData)
|
||||
@objc public class func parseData(_ serializedData: Data) throws -> SNProtoSharedConfigMessage {
|
||||
let proto = try SessionProtos_SharedConfigMessage(serializedData: serializedData)
|
||||
return try parseProto(proto)
|
||||
}
|
||||
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_GroupContext) throws -> SNProtoGroupContext {
|
||||
guard proto.hasID else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: id")
|
||||
fileprivate class func parseProto(_ proto: SessionProtos_SharedConfigMessage) throws -> SNProtoSharedConfigMessage {
|
||||
guard proto.hasKind else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: kind")
|
||||
}
|
||||
let id = proto.id
|
||||
let kind = SNProtoSharedConfigMessageKindWrap(proto.kind)
|
||||
|
||||
guard proto.hasType else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: type")
|
||||
guard proto.hasSeqno else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: seqno")
|
||||
}
|
||||
let type = SNProtoGroupContextTypeWrap(proto.type)
|
||||
let seqno = proto.seqno
|
||||
|
||||
var avatar: SNProtoAttachmentPointer? = nil
|
||||
if proto.hasAvatar {
|
||||
avatar = try SNProtoAttachmentPointer.parseProto(proto.avatar)
|
||||
guard proto.hasData else {
|
||||
throw SNProtoError.invalidProtobuf(description: "\(logTag) missing required field: data")
|
||||
}
|
||||
let data = proto.data
|
||||
|
||||
// MARK: - Begin Validation Logic for SNProtoGroupContext -
|
||||
// MARK: - Begin Validation Logic for SNProtoSharedConfigMessage -
|
||||
|
||||
// MARK: - End Validation Logic for SNProtoGroupContext -
|
||||
// MARK: - End Validation Logic for SNProtoSharedConfigMessage -
|
||||
|
||||
let result = SNProtoGroupContext(proto: proto,
|
||||
id: id,
|
||||
type: type,
|
||||
avatar: avatar)
|
||||
let result = SNProtoSharedConfigMessage(proto: proto,
|
||||
kind: kind,
|
||||
seqno: seqno,
|
||||
data: data)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -3898,14 +3837,14 @@ extension SNProtoAttachmentPointer.SNProtoAttachmentPointerBuilder {
|
|||
|
||||
#if DEBUG
|
||||
|
||||
extension SNProtoGroupContext {
|
||||
extension SNProtoSharedConfigMessage {
|
||||
@objc public func serializedDataIgnoringErrors() -> Data? {
|
||||
return try! self.serializedData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SNProtoGroupContext.SNProtoGroupContextBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SNProtoGroupContext? {
|
||||
extension SNProtoSharedConfigMessage.SNProtoSharedConfigMessageBuilder {
|
||||
@objc public func buildIgnoringErrors() -> SNProtoSharedConfigMessage? {
|
||||
return try! self.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -348,6 +348,15 @@ struct SessionProtos_Content {
|
|||
/// Clears the value of `messageRequestResponse`. Subsequent reads from it will return its default value.
|
||||
mutating func clearMessageRequestResponse() {_uniqueStorage()._messageRequestResponse = nil}
|
||||
|
||||
var sharedConfigMessage: SessionProtos_SharedConfigMessage {
|
||||
get {return _storage._sharedConfigMessage ?? SessionProtos_SharedConfigMessage()}
|
||||
set {_uniqueStorage()._sharedConfigMessage = newValue}
|
||||
}
|
||||
/// Returns true if `sharedConfigMessage` has been explicitly set.
|
||||
var hasSharedConfigMessage: Bool {return _storage._sharedConfigMessage != nil}
|
||||
/// Clears the value of `sharedConfigMessage`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSharedConfigMessage() {_uniqueStorage()._sharedConfigMessage = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
@ -591,15 +600,7 @@ struct SessionProtos_DataMessage {
|
|||
set {_uniqueStorage()._attachments = newValue}
|
||||
}
|
||||
|
||||
var group: SessionProtos_GroupContext {
|
||||
get {return _storage._group ?? SessionProtos_GroupContext()}
|
||||
set {_uniqueStorage()._group = newValue}
|
||||
}
|
||||
/// Returns true if `group` has been explicitly set.
|
||||
var hasGroup: Bool {return _storage._group != nil}
|
||||
/// Clears the value of `group`. Subsequent reads from it will return its default value.
|
||||
mutating func clearGroup() {_uniqueStorage()._group = nil}
|
||||
|
||||
/// optional GroupContext group = 3; // No longer used
|
||||
var flags: UInt32 {
|
||||
get {return _storage._flags ?? 0}
|
||||
set {_uniqueStorage()._flags = newValue}
|
||||
|
@ -1580,91 +1581,61 @@ extension SessionProtos_AttachmentPointer.Flags: CaseIterable {
|
|||
|
||||
#endif // swift(>=4.2)
|
||||
|
||||
struct SessionProtos_GroupContext {
|
||||
struct SessionProtos_SharedConfigMessage {
|
||||
// SwiftProtobuf.Message conformance is added in an extension below. See the
|
||||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
/// @required
|
||||
var id: Data {
|
||||
get {return _storage._id ?? Data()}
|
||||
set {_uniqueStorage()._id = newValue}
|
||||
var kind: SessionProtos_SharedConfigMessage.Kind {
|
||||
get {return _kind ?? .userProfile}
|
||||
set {_kind = newValue}
|
||||
}
|
||||
/// Returns true if `id` has been explicitly set.
|
||||
var hasID: Bool {return _storage._id != nil}
|
||||
/// Clears the value of `id`. Subsequent reads from it will return its default value.
|
||||
mutating func clearID() {_uniqueStorage()._id = nil}
|
||||
/// Returns true if `kind` has been explicitly set.
|
||||
var hasKind: Bool {return self._kind != nil}
|
||||
/// Clears the value of `kind`. Subsequent reads from it will return its default value.
|
||||
mutating func clearKind() {self._kind = nil}
|
||||
|
||||
/// @required
|
||||
var type: SessionProtos_GroupContext.TypeEnum {
|
||||
get {return _storage._type ?? .unknown}
|
||||
set {_uniqueStorage()._type = newValue}
|
||||
var seqno: Int64 {
|
||||
get {return _seqno ?? 0}
|
||||
set {_seqno = newValue}
|
||||
}
|
||||
/// Returns true if `type` has been explicitly set.
|
||||
var hasType: Bool {return _storage._type != nil}
|
||||
/// Clears the value of `type`. Subsequent reads from it will return its default value.
|
||||
mutating func clearType() {_uniqueStorage()._type = nil}
|
||||
/// Returns true if `seqno` has been explicitly set.
|
||||
var hasSeqno: Bool {return self._seqno != nil}
|
||||
/// Clears the value of `seqno`. Subsequent reads from it will return its default value.
|
||||
mutating func clearSeqno() {self._seqno = nil}
|
||||
|
||||
var name: String {
|
||||
get {return _storage._name ?? String()}
|
||||
set {_uniqueStorage()._name = newValue}
|
||||
}
|
||||
/// Returns true if `name` has been explicitly set.
|
||||
var hasName: Bool {return _storage._name != nil}
|
||||
/// Clears the value of `name`. Subsequent reads from it will return its default value.
|
||||
mutating func clearName() {_uniqueStorage()._name = nil}
|
||||
|
||||
var members: [String] {
|
||||
get {return _storage._members}
|
||||
set {_uniqueStorage()._members = newValue}
|
||||
}
|
||||
|
||||
var avatar: SessionProtos_AttachmentPointer {
|
||||
get {return _storage._avatar ?? SessionProtos_AttachmentPointer()}
|
||||
set {_uniqueStorage()._avatar = newValue}
|
||||
}
|
||||
/// Returns true if `avatar` has been explicitly set.
|
||||
var hasAvatar: Bool {return _storage._avatar != nil}
|
||||
/// Clears the value of `avatar`. Subsequent reads from it will return its default value.
|
||||
mutating func clearAvatar() {_uniqueStorage()._avatar = nil}
|
||||
|
||||
var admins: [String] {
|
||||
get {return _storage._admins}
|
||||
set {_uniqueStorage()._admins = newValue}
|
||||
/// @required
|
||||
var data: Data {
|
||||
get {return _data ?? Data()}
|
||||
set {_data = newValue}
|
||||
}
|
||||
/// Returns true if `data` has been explicitly set.
|
||||
var hasData: Bool {return self._data != nil}
|
||||
/// Clears the value of `data`. Subsequent reads from it will return its default value.
|
||||
mutating func clearData() {self._data = nil}
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
enum TypeEnum: SwiftProtobuf.Enum {
|
||||
enum Kind: SwiftProtobuf.Enum {
|
||||
typealias RawValue = Int
|
||||
case unknown // = 0
|
||||
case update // = 1
|
||||
case deliver // = 2
|
||||
case quit // = 3
|
||||
case requestInfo // = 4
|
||||
case userProfile // = 1
|
||||
|
||||
init() {
|
||||
self = .unknown
|
||||
self = .userProfile
|
||||
}
|
||||
|
||||
init?(rawValue: Int) {
|
||||
switch rawValue {
|
||||
case 0: self = .unknown
|
||||
case 1: self = .update
|
||||
case 2: self = .deliver
|
||||
case 3: self = .quit
|
||||
case 4: self = .requestInfo
|
||||
case 1: self = .userProfile
|
||||
default: return nil
|
||||
}
|
||||
}
|
||||
|
||||
var rawValue: Int {
|
||||
switch self {
|
||||
case .unknown: return 0
|
||||
case .update: return 1
|
||||
case .deliver: return 2
|
||||
case .quit: return 3
|
||||
case .requestInfo: return 4
|
||||
case .userProfile: return 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1672,12 +1643,14 @@ struct SessionProtos_GroupContext {
|
|||
|
||||
init() {}
|
||||
|
||||
fileprivate var _storage = _StorageClass.defaultInstance
|
||||
fileprivate var _kind: SessionProtos_SharedConfigMessage.Kind? = nil
|
||||
fileprivate var _seqno: Int64? = nil
|
||||
fileprivate var _data: Data? = nil
|
||||
}
|
||||
|
||||
#if swift(>=4.2)
|
||||
|
||||
extension SessionProtos_GroupContext.TypeEnum: CaseIterable {
|
||||
extension SessionProtos_SharedConfigMessage.Kind: CaseIterable {
|
||||
// Support synthesized by the compiler.
|
||||
}
|
||||
|
||||
|
@ -1933,6 +1906,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
8: .same(proto: "dataExtractionNotification"),
|
||||
9: .same(proto: "unsendRequest"),
|
||||
10: .same(proto: "messageRequestResponse"),
|
||||
11: .same(proto: "sharedConfigMessage"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
|
@ -1944,6 +1918,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
var _dataExtractionNotification: SessionProtos_DataExtractionNotification? = nil
|
||||
var _unsendRequest: SessionProtos_UnsendRequest? = nil
|
||||
var _messageRequestResponse: SessionProtos_MessageRequestResponse? = nil
|
||||
var _sharedConfigMessage: SessionProtos_SharedConfigMessage? = nil
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
|
@ -1958,6 +1933,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
_dataExtractionNotification = source._dataExtractionNotification
|
||||
_unsendRequest = source._unsendRequest
|
||||
_messageRequestResponse = source._messageRequestResponse
|
||||
_sharedConfigMessage = source._sharedConfigMessage
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1978,6 +1954,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
if let v = _storage._dataExtractionNotification, !v.isInitialized {return false}
|
||||
if let v = _storage._unsendRequest, !v.isInitialized {return false}
|
||||
if let v = _storage._messageRequestResponse, !v.isInitialized {return false}
|
||||
if let v = _storage._sharedConfigMessage, !v.isInitialized {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1998,6 +1975,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
case 8: try { try decoder.decodeSingularMessageField(value: &_storage._dataExtractionNotification) }()
|
||||
case 9: try { try decoder.decodeSingularMessageField(value: &_storage._unsendRequest) }()
|
||||
case 10: try { try decoder.decodeSingularMessageField(value: &_storage._messageRequestResponse) }()
|
||||
case 11: try { try decoder.decodeSingularMessageField(value: &_storage._sharedConfigMessage) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
@ -2034,6 +2012,9 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
try { if let v = _storage._messageRequestResponse {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 10)
|
||||
} }()
|
||||
try { if let v = _storage._sharedConfigMessage {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 11)
|
||||
} }()
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
@ -2051,6 +2032,7 @@ extension SessionProtos_Content: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
if _storage._dataExtractionNotification != rhs_storage._dataExtractionNotification {return false}
|
||||
if _storage._unsendRequest != rhs_storage._unsendRequest {return false}
|
||||
if _storage._messageRequestResponse != rhs_storage._messageRequestResponse {return false}
|
||||
if _storage._sharedConfigMessage != rhs_storage._sharedConfigMessage {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
|
@ -2286,7 +2268,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "body"),
|
||||
2: .same(proto: "attachments"),
|
||||
3: .same(proto: "group"),
|
||||
4: .same(proto: "flags"),
|
||||
5: .same(proto: "expireTimer"),
|
||||
6: .same(proto: "profileKey"),
|
||||
|
@ -2303,7 +2284,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
fileprivate class _StorageClass {
|
||||
var _body: String? = nil
|
||||
var _attachments: [SessionProtos_AttachmentPointer] = []
|
||||
var _group: SessionProtos_GroupContext? = nil
|
||||
var _flags: UInt32? = nil
|
||||
var _expireTimer: UInt32? = nil
|
||||
var _profileKey: Data? = nil
|
||||
|
@ -2323,7 +2303,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
init(copying source: _StorageClass) {
|
||||
_body = source._body
|
||||
_attachments = source._attachments
|
||||
_group = source._group
|
||||
_flags = source._flags
|
||||
_expireTimer = source._expireTimer
|
||||
_profileKey = source._profileKey
|
||||
|
@ -2348,7 +2327,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
public var isInitialized: Bool {
|
||||
return withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
if !SwiftProtobuf.Internal.areAllInitialized(_storage._attachments) {return false}
|
||||
if let v = _storage._group, !v.isInitialized {return false}
|
||||
if let v = _storage._quote, !v.isInitialized {return false}
|
||||
if !SwiftProtobuf.Internal.areAllInitialized(_storage._preview) {return false}
|
||||
if let v = _storage._reaction, !v.isInitialized {return false}
|
||||
|
@ -2368,7 +2346,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &_storage._body) }()
|
||||
case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._attachments) }()
|
||||
case 3: try { try decoder.decodeSingularMessageField(value: &_storage._group) }()
|
||||
case 4: try { try decoder.decodeSingularUInt32Field(value: &_storage._flags) }()
|
||||
case 5: try { try decoder.decodeSingularUInt32Field(value: &_storage._expireTimer) }()
|
||||
case 6: try { try decoder.decodeSingularBytesField(value: &_storage._profileKey) }()
|
||||
|
@ -2398,9 +2375,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
if !_storage._attachments.isEmpty {
|
||||
try visitor.visitRepeatedMessageField(value: _storage._attachments, fieldNumber: 2)
|
||||
}
|
||||
try { if let v = _storage._group {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
try { if let v = _storage._flags {
|
||||
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4)
|
||||
} }()
|
||||
|
@ -2445,7 +2419,6 @@ extension SessionProtos_DataMessage: SwiftProtobuf.Message, SwiftProtobuf._Messa
|
|||
let rhs_storage = _args.1
|
||||
if _storage._body != rhs_storage._body {return false}
|
||||
if _storage._attachments != rhs_storage._attachments {return false}
|
||||
if _storage._group != rhs_storage._group {return false}
|
||||
if _storage._flags != rhs_storage._flags {return false}
|
||||
if _storage._expireTimer != rhs_storage._expireTimer {return false}
|
||||
if _storage._profileKey != rhs_storage._profileKey {return false}
|
||||
|
@ -3301,127 +3274,63 @@ extension SessionProtos_AttachmentPointer.Flags: SwiftProtobuf._ProtoNameProvidi
|
|||
]
|
||||
}
|
||||
|
||||
extension SessionProtos_GroupContext: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".GroupContext"
|
||||
extension SessionProtos_SharedConfigMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = _protobuf_package + ".SharedConfigMessage"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "id"),
|
||||
2: .same(proto: "type"),
|
||||
3: .same(proto: "name"),
|
||||
4: .same(proto: "members"),
|
||||
5: .same(proto: "avatar"),
|
||||
6: .same(proto: "admins"),
|
||||
1: .same(proto: "kind"),
|
||||
2: .same(proto: "seqno"),
|
||||
3: .same(proto: "data"),
|
||||
]
|
||||
|
||||
fileprivate class _StorageClass {
|
||||
var _id: Data? = nil
|
||||
var _type: SessionProtos_GroupContext.TypeEnum? = nil
|
||||
var _name: String? = nil
|
||||
var _members: [String] = []
|
||||
var _avatar: SessionProtos_AttachmentPointer? = nil
|
||||
var _admins: [String] = []
|
||||
|
||||
static let defaultInstance = _StorageClass()
|
||||
|
||||
private init() {}
|
||||
|
||||
init(copying source: _StorageClass) {
|
||||
_id = source._id
|
||||
_type = source._type
|
||||
_name = source._name
|
||||
_members = source._members
|
||||
_avatar = source._avatar
|
||||
_admins = source._admins
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate mutating func _uniqueStorage() -> _StorageClass {
|
||||
if !isKnownUniquelyReferenced(&_storage) {
|
||||
_storage = _StorageClass(copying: _storage)
|
||||
}
|
||||
return _storage
|
||||
}
|
||||
|
||||
public var isInitialized: Bool {
|
||||
return withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
if let v = _storage._avatar, !v.isInitialized {return false}
|
||||
return true
|
||||
}
|
||||
if self._kind == nil {return false}
|
||||
if self._seqno == nil {return false}
|
||||
if self._data == nil {return false}
|
||||
return true
|
||||
}
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
_ = _uniqueStorage()
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularBytesField(value: &_storage._id) }()
|
||||
case 2: try { try decoder.decodeSingularEnumField(value: &_storage._type) }()
|
||||
case 3: try { try decoder.decodeSingularStringField(value: &_storage._name) }()
|
||||
case 4: try { try decoder.decodeRepeatedStringField(value: &_storage._members) }()
|
||||
case 5: try { try decoder.decodeSingularMessageField(value: &_storage._avatar) }()
|
||||
case 6: try { try decoder.decodeRepeatedStringField(value: &_storage._admins) }()
|
||||
default: break
|
||||
}
|
||||
while let fieldNumber = try decoder.nextFieldNumber() {
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularEnumField(value: &self._kind) }()
|
||||
case 2: try { try decoder.decodeSingularInt64Field(value: &self._seqno) }()
|
||||
case 3: try { try decoder.decodeSingularBytesField(value: &self._data) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = _storage._id {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = _storage._type {
|
||||
try visitor.visitSingularEnumField(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try { if let v = _storage._name {
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
if !_storage._members.isEmpty {
|
||||
try visitor.visitRepeatedStringField(value: _storage._members, fieldNumber: 4)
|
||||
}
|
||||
try { if let v = _storage._avatar {
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 5)
|
||||
} }()
|
||||
if !_storage._admins.isEmpty {
|
||||
try visitor.visitRepeatedStringField(value: _storage._admins, fieldNumber: 6)
|
||||
}
|
||||
}
|
||||
// The use of inline closures is to circumvent an issue where the compiler
|
||||
// allocates stack space for every if/case branch local when no optimizations
|
||||
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
|
||||
// https://github.com/apple/swift-protobuf/issues/1182
|
||||
try { if let v = self._kind {
|
||||
try visitor.visitSingularEnumField(value: v, fieldNumber: 1)
|
||||
} }()
|
||||
try { if let v = self._seqno {
|
||||
try visitor.visitSingularInt64Field(value: v, fieldNumber: 2)
|
||||
} }()
|
||||
try { if let v = self._data {
|
||||
try visitor.visitSingularBytesField(value: v, fieldNumber: 3)
|
||||
} }()
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: SessionProtos_GroupContext, rhs: SessionProtos_GroupContext) -> Bool {
|
||||
if lhs._storage !== rhs._storage {
|
||||
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
|
||||
let _storage = _args.0
|
||||
let rhs_storage = _args.1
|
||||
if _storage._id != rhs_storage._id {return false}
|
||||
if _storage._type != rhs_storage._type {return false}
|
||||
if _storage._name != rhs_storage._name {return false}
|
||||
if _storage._members != rhs_storage._members {return false}
|
||||
if _storage._avatar != rhs_storage._avatar {return false}
|
||||
if _storage._admins != rhs_storage._admins {return false}
|
||||
return true
|
||||
}
|
||||
if !storagesAreEqual {return false}
|
||||
}
|
||||
static func ==(lhs: SessionProtos_SharedConfigMessage, rhs: SessionProtos_SharedConfigMessage) -> Bool {
|
||||
if lhs._kind != rhs._kind {return false}
|
||||
if lhs._seqno != rhs._seqno {return false}
|
||||
if lhs._data != rhs._data {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension SessionProtos_GroupContext.TypeEnum: SwiftProtobuf._ProtoNameProviding {
|
||||
extension SessionProtos_SharedConfigMessage.Kind: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "UNKNOWN"),
|
||||
1: .same(proto: "UPDATE"),
|
||||
2: .same(proto: "DELIVER"),
|
||||
3: .same(proto: "QUIT"),
|
||||
4: .same(proto: "REQUEST_INFO"),
|
||||
1: .same(proto: "USER_PROFILE"),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ message Content {
|
|||
optional DataExtractionNotification dataExtractionNotification = 8;
|
||||
optional UnsendRequest unsendRequest = 9;
|
||||
optional MessageRequestResponse messageRequestResponse = 10;
|
||||
optional SharedConfigMessage sharedConfigMessage = 11;
|
||||
}
|
||||
|
||||
message CallMessage {
|
||||
|
@ -193,7 +194,7 @@ message DataMessage {
|
|||
|
||||
optional string body = 1;
|
||||
repeated AttachmentPointer attachments = 2;
|
||||
optional GroupContext group = 3;
|
||||
// optional GroupContext group = 3; // No longer used
|
||||
optional uint32 flags = 4;
|
||||
optional uint32 expireTimer = 5;
|
||||
optional bytes profileKey = 6;
|
||||
|
@ -271,22 +272,15 @@ message AttachmentPointer {
|
|||
optional string url = 101;
|
||||
}
|
||||
|
||||
message GroupContext {
|
||||
message SharedConfigMessage {
|
||||
enum Kind {
|
||||
USER_PROFILE = 1;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
UPDATE = 1;
|
||||
DELIVER = 2;
|
||||
QUIT = 3;
|
||||
REQUEST_INFO = 4;
|
||||
}
|
||||
|
||||
// @required
|
||||
optional bytes id = 1;
|
||||
// @required
|
||||
optional Type type = 2;
|
||||
optional string name = 3;
|
||||
repeated string members = 4;
|
||||
optional AttachmentPointer avatar = 5;
|
||||
repeated string admins = 6;
|
||||
// @required
|
||||
required Kind kind = 1;
|
||||
// @required
|
||||
required int64 seqno = 2;
|
||||
// @required
|
||||
required bytes data = 3;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@ public enum MessageReceiverError: LocalizedError {
|
|||
case decryptionFailed
|
||||
case invalidGroupPublicKey
|
||||
case noGroupKeyPair
|
||||
case invalidSharedConfigMessageHandling
|
||||
|
||||
public var isRetryable: Bool {
|
||||
switch self {
|
||||
case .duplicateMessage, .duplicateMessageNewSnode, .duplicateControlMessage,
|
||||
.invalidMessage, .unknownMessage, .unknownEnvelopeType, .invalidSignature,
|
||||
.noData, .senderBlocked, .noThread, .selfSend, .decryptionFailed:
|
||||
.noData, .senderBlocked, .noThread, .selfSend, .decryptionFailed,
|
||||
.invalidSharedConfigMessageHandling:
|
||||
return false
|
||||
|
||||
default: return true
|
||||
|
@ -51,6 +53,8 @@ public enum MessageReceiverError: LocalizedError {
|
|||
// Shared sender keys
|
||||
case .invalidGroupPublicKey: return "Invalid group public key."
|
||||
case .noGroupKeyPair: return "Missing group key pair."
|
||||
|
||||
case .invalidSharedConfigMessageHandling: return "Invalid handling of a shared config message"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageReceiver {
|
||||
|
@ -29,7 +28,7 @@ extension MessageReceiver {
|
|||
publicKey: userPublicKey,
|
||||
name: message.displayName,
|
||||
profilePictureUrl: message.profilePictureUrl,
|
||||
profileKey: OWSAES256Key(data: message.profileKey),
|
||||
profileKey: message.profileKey,
|
||||
sentTimestamp: messageSentTimestamp
|
||||
)
|
||||
try Contact(id: userPublicKey)
|
||||
|
@ -73,15 +72,13 @@ extension MessageReceiver {
|
|||
if
|
||||
profile.name != contactInfo.displayName ||
|
||||
profile.profilePictureUrl != contactInfo.profilePictureUrl ||
|
||||
profile.profileEncryptionKey != contactInfo.profileKey.map({ OWSAES256Key(data: $0) })
|
||||
profile.profileEncryptionKey != contactInfo.profileKey
|
||||
{
|
||||
try profile
|
||||
.with(
|
||||
name: contactInfo.displayName,
|
||||
profilePictureUrl: .updateIf(contactInfo.profilePictureUrl),
|
||||
profileEncryptionKey: .updateIf(
|
||||
contactInfo.profileKey.map { OWSAES256Key(data: $0) }
|
||||
)
|
||||
profileEncryptionKey: .updateIf(contactInfo.profileKey)
|
||||
)
|
||||
.save(db)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageReceiver {
|
||||
|
@ -21,17 +20,14 @@ extension MessageReceiver {
|
|||
// Update profile if needed (want to do this regardless of whether the message exists or
|
||||
// not to ensure the profile info gets sync between a users devices at every chance)
|
||||
if let profile = message.profile {
|
||||
var contactProfileKey: OWSAES256Key? = nil
|
||||
let messageSentTimestamp: TimeInterval = (TimeInterval(message.sentTimestamp ?? 0) / 1000)
|
||||
|
||||
if let profileKey = profile.profileKey { contactProfileKey = OWSAES256Key(data: profileKey) }
|
||||
|
||||
try MessageReceiver.updateProfileIfNeeded(
|
||||
db,
|
||||
publicKey: senderId,
|
||||
name: profile.displayName,
|
||||
profilePictureUrl: profile.profilePictureUrl,
|
||||
profileKey: contactProfileKey,
|
||||
profileKey: profile.profileKey,
|
||||
sentTimestamp: messageSentTimestamp
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageReceiver {
|
||||
|
@ -26,15 +25,12 @@ extension MessageReceiver {
|
|||
// Update profile if needed (want to do this regardless of whether the message exists or
|
||||
// not to ensure the profile info gets sync between a users devices at every chance)
|
||||
if let profile = message.profile {
|
||||
var contactProfileKey: OWSAES256Key? = nil
|
||||
if let profileKey = profile.profileKey { contactProfileKey = OWSAES256Key(data: profileKey) }
|
||||
|
||||
try MessageReceiver.updateProfileIfNeeded(
|
||||
db,
|
||||
publicKey: sender,
|
||||
name: profile.displayName,
|
||||
profilePictureUrl: profile.profilePictureUrl,
|
||||
profileKey: contactProfileKey,
|
||||
profileKey: profile.profileKey,
|
||||
sentTimestamp: messageSentTimestamp
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import Sodium
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum MessageReceiver {
|
||||
|
@ -218,6 +217,9 @@ public enum MessageReceiver {
|
|||
openGroupId: openGroupId
|
||||
)
|
||||
|
||||
// SharedConfigMessages should be handled by the 'SharedUtil' instead of this
|
||||
case is SharedConfigMessage: throw MessageReceiverError.invalidSharedConfigMessageHandling
|
||||
|
||||
default: fatalError()
|
||||
}
|
||||
|
||||
|
@ -309,7 +311,7 @@ public enum MessageReceiver {
|
|||
publicKey: String,
|
||||
name: String?,
|
||||
profilePictureUrl: String?,
|
||||
profileKey: OWSAES256Key?,
|
||||
profileKey: Data?,
|
||||
sentTimestamp: TimeInterval,
|
||||
dependencies: Dependencies = Dependencies()
|
||||
) throws {
|
||||
|
@ -341,9 +343,9 @@ public enum MessageReceiver {
|
|||
|
||||
// Profile picture & profile key
|
||||
if
|
||||
let profileKey: OWSAES256Key = profileKey,
|
||||
let profileKey: Data = profileKey,
|
||||
let profilePictureUrl: String = profilePictureUrl,
|
||||
profileKey.keyData.count == kAES256_KeyByteLength,
|
||||
profileKey.count == ProfileManager.avatarAES256KeyByteLength,
|
||||
profileKey != profile.profileEncryptionKey
|
||||
{
|
||||
let shouldUpdate: Bool
|
||||
|
|
|
@ -106,8 +106,8 @@ extension MessageSender {
|
|||
if let interactionId: Int64 = interactionId {
|
||||
let threadId: String = {
|
||||
switch destination {
|
||||
case .contact(let publicKey): return publicKey
|
||||
case .closedGroup(let groupPublicKey): return groupPublicKey
|
||||
case .contact(let publicKey, _): return publicKey
|
||||
case .closedGroup(let groupPublicKey, _): return groupPublicKey
|
||||
case .openGroup(let roomToken, let server, _, _, _):
|
||||
return OpenGroup.idFor(roomToken: roomToken, server: server)
|
||||
|
||||
|
@ -194,16 +194,53 @@ extension MessageSender {
|
|||
guard Identity.userExists(db) else { return Promise(error: StorageError.generic) }
|
||||
|
||||
let publicKey: String = getUserHexEncodedPublicKey(db)
|
||||
let destination: Message.Destination = Message.Destination.contact(publicKey: publicKey)
|
||||
let configurationMessage = try ConfigurationMessage.getCurrent(db)
|
||||
let legacyDestination: Message.Destination = Message.Destination.contact(
|
||||
publicKey: publicKey,
|
||||
namespace: .default
|
||||
)
|
||||
let legacyConfigurationMessage = try ConfigurationMessage.getCurrent(db)
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
|
||||
let userConfigMessageChanges: [SharedConfigMessage] = SessionUtil.getChanges()
|
||||
let destination: Message.Destination = Message.Destination.contact(
|
||||
publicKey: publicKey,
|
||||
namespace: .userProfileConfig
|
||||
)
|
||||
|
||||
if forceSyncNow {
|
||||
try MessageSender
|
||||
.sendImmediate(db, message: configurationMessage, to: destination, interactionId: nil)
|
||||
.sendImmediate(db, message: legacyConfigurationMessage, to: legacyDestination, interactionId: nil)
|
||||
.done { seal.fulfill(()) }
|
||||
.catch { _ in seal.reject(StorageError.generic) }
|
||||
.retainUntilComplete()
|
||||
when(
|
||||
resolved: try userConfigMessageChanges.map { message in
|
||||
try MessageSender
|
||||
.sendImmediate(
|
||||
db,
|
||||
message: message,
|
||||
to: destination,
|
||||
interactionId: nil
|
||||
)
|
||||
}
|
||||
)
|
||||
.done { results in
|
||||
let hadError: Bool = results.contains { result in
|
||||
switch result {
|
||||
case .fulfilled: return false
|
||||
case .rejected: return true
|
||||
}
|
||||
}
|
||||
|
||||
guard !hadError else {
|
||||
seal.reject(StorageError.generic)
|
||||
return
|
||||
}
|
||||
|
||||
seal.fulfill(())
|
||||
}
|
||||
.catch { _ in seal.reject(StorageError.generic) }
|
||||
.retainUntilComplete()
|
||||
}
|
||||
else {
|
||||
JobRunner.add(
|
||||
|
@ -212,8 +249,8 @@ extension MessageSender {
|
|||
variant: .messageSend,
|
||||
threadId: publicKey,
|
||||
details: MessageSendJob.Details(
|
||||
destination: destination,
|
||||
message: configurationMessage
|
||||
destination: legacyDestination,
|
||||
message: legacyConfigurationMessage
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -77,8 +77,8 @@ public final class MessageSender {
|
|||
message.sender = userPublicKey
|
||||
message.recipient = {
|
||||
switch destination {
|
||||
case .contact(let publicKey): return publicKey
|
||||
case .closedGroup(let groupPublicKey): return groupPublicKey
|
||||
case .contact(let publicKey, _): return publicKey
|
||||
case .closedGroup(let groupPublicKey, _): return groupPublicKey
|
||||
case .openGroup, .openGroupInbox: preconditionFailure()
|
||||
}
|
||||
}()
|
||||
|
@ -112,7 +112,7 @@ public final class MessageSender {
|
|||
if var messageWithProfile: MessageWithProfile = message as? MessageWithProfile {
|
||||
let profile: Profile = Profile.fetchOrCreateCurrentUser(db)
|
||||
|
||||
if let profileKey: Data = profile.profileEncryptionKey?.keyData, let profilePictureUrl: String = profile.profilePictureUrl {
|
||||
if let profileKey: Data = profile.profileEncryptionKey, let profilePictureUrl: String = profile.profilePictureUrl {
|
||||
messageWithProfile.profile = VisibleMessage.VMProfile(
|
||||
displayName: profile.name,
|
||||
profileKey: profileKey,
|
||||
|
@ -146,10 +146,10 @@ public final class MessageSender {
|
|||
let ciphertext: Data
|
||||
do {
|
||||
switch destination {
|
||||
case .contact(let publicKey):
|
||||
case .contact(let publicKey, _):
|
||||
ciphertext = try encryptWithSessionProtocol(plaintext, for: publicKey)
|
||||
|
||||
case .closedGroup(let groupPublicKey):
|
||||
case .closedGroup(let groupPublicKey, _):
|
||||
guard let encryptionKeyPair: ClosedGroupKeyPair = try? ClosedGroupKeyPair.fetchLatestKeyPair(db, threadId: groupPublicKey) else {
|
||||
throw MessageSenderError.noKeyPair
|
||||
}
|
||||
|
@ -171,15 +171,18 @@ public final class MessageSender {
|
|||
// Wrap the result
|
||||
let kind: SNProtoEnvelope.SNProtoEnvelopeType
|
||||
let senderPublicKey: String
|
||||
let namespace: SnodeAPI.Namespace
|
||||
|
||||
switch destination {
|
||||
case .contact:
|
||||
case .contact(_, let targetNamespace):
|
||||
kind = .sessionMessage
|
||||
senderPublicKey = ""
|
||||
namespace = targetNamespace
|
||||
|
||||
case .closedGroup(let groupPublicKey):
|
||||
case .closedGroup(let groupPublicKey, let targetNamespace):
|
||||
kind = .closedGroupMessage
|
||||
senderPublicKey = groupPublicKey
|
||||
namespace = targetNamespace
|
||||
|
||||
case .openGroup, .openGroupInbox: preconditionFailure()
|
||||
}
|
||||
|
@ -208,8 +211,7 @@ public final class MessageSender {
|
|||
SnodeAPI
|
||||
.sendMessage(
|
||||
snodeMessage,
|
||||
isClosedGroupMessage: (kind == .closedGroupMessage),
|
||||
isConfigMessage: (message is ConfigurationMessage)
|
||||
in: namespace
|
||||
)
|
||||
.done(on: DispatchQueue.global(qos: .default)) { promises in
|
||||
let promiseCount = promises.count
|
||||
|
@ -488,7 +490,7 @@ public final class MessageSender {
|
|||
if let message: VisibleMessage = message as? VisibleMessage {
|
||||
let profile: Profile = Profile.fetchOrCreateCurrentUser(db)
|
||||
|
||||
if let profileKey: Data = profile.profileEncryptionKey?.keyData, let profilePictureUrl: String = profile.profilePictureUrl {
|
||||
if let profileKey: Data = profile.profileEncryptionKey, let profilePictureUrl: String = profile.profilePictureUrl {
|
||||
message.profile = VisibleMessage.VMProfile(
|
||||
displayName: profile.name,
|
||||
profileKey: profileKey,
|
||||
|
@ -627,8 +629,8 @@ public final class MessageSender {
|
|||
try? ControlMessageProcessRecord(
|
||||
threadId: {
|
||||
switch destination {
|
||||
case .contact(let publicKey): return publicKey
|
||||
case .closedGroup(let groupPublicKey): return groupPublicKey
|
||||
case .contact(let publicKey, _): return publicKey
|
||||
case .closedGroup(let groupPublicKey, _): return groupPublicKey
|
||||
case .openGroup(let roomToken, let server, _, _, _):
|
||||
return OpenGroup.idFor(roomToken: roomToken, server: server)
|
||||
|
||||
|
@ -644,7 +646,7 @@ public final class MessageSender {
|
|||
// • the destination was a contact
|
||||
// • we didn't sync it already
|
||||
let userPublicKey = getUserHexEncodedPublicKey(db)
|
||||
if case .contact(let publicKey) = destination, !isSyncMessage {
|
||||
if case .contact(let publicKey, let namespace) = destination, !isSyncMessage {
|
||||
if let message = message as? VisibleMessage { message.syncTarget = publicKey }
|
||||
if let message = message as? ExpirationTimerUpdate { message.syncTarget = publicKey }
|
||||
|
||||
|
@ -652,7 +654,7 @@ public final class MessageSender {
|
|||
try sendToSnodeDestination(
|
||||
db,
|
||||
message: message,
|
||||
to: .contact(publicKey: userPublicKey),
|
||||
to: .contact(publicKey: userPublicKey, namespace: namespace),
|
||||
interactionId: interactionId,
|
||||
isSyncMessage: true
|
||||
).retainUntilComplete()
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public final class CurrentUserPoller: Poller {
|
||||
public static var namespaces: [SnodeAPI.Namespace] = [.default, .userProfileConfig]
|
||||
|
||||
private var targetSnode: Atomic<Snode?> = Atomic(nil)
|
||||
private var usedSnodes: Atomic<Set<Snode>> = Atomic([])
|
||||
|
||||
// MARK: - Settings
|
||||
|
||||
override var namespaces: [SnodeAPI.Namespace] { CurrentUserPoller.namespaces }
|
||||
|
||||
/// After polling a given snode this many times we always switch to a new one.
|
||||
///
|
||||
/// The reason for doing this is that sometimes a snode will be giving us successful responses while
|
||||
/// it isn't actually getting messages from other snodes.
|
||||
override var maxNodePollCount: UInt { 6 }
|
||||
|
||||
private let pollInterval: TimeInterval = 1.5
|
||||
private let retryInterval: TimeInterval = 0.25
|
||||
private let maxRetryInterval: TimeInterval = 15
|
||||
|
||||
// MARK: - Convenience Functions
|
||||
|
||||
public func start() {
|
||||
let publicKey: String = getUserHexEncodedPublicKey()
|
||||
|
||||
guard isPolling.wrappedValue[publicKey] != true else { return }
|
||||
|
||||
SNLog("Started polling.")
|
||||
super.startIfNeeded(for: publicKey)
|
||||
}
|
||||
|
||||
public func stop() {
|
||||
SNLog("Stopped polling.")
|
||||
super.stopAllPollers()
|
||||
}
|
||||
|
||||
// MARK: - Abstract Methods
|
||||
|
||||
override func pollerName(for publicKey: String) -> String {
|
||||
return "Main Poller"
|
||||
}
|
||||
|
||||
override func nextPollDelay(for publicKey: String) -> TimeInterval {
|
||||
let failureCount: TimeInterval = TimeInterval(failureCount.wrappedValue[publicKey] ?? 0)
|
||||
|
||||
// If there have been no failures then just use the 'minPollInterval'
|
||||
guard failureCount > 0 else { return pollInterval }
|
||||
|
||||
// Otherwise use a simple back-off with the 'retryInterval'
|
||||
let nextDelay: TimeInterval = (retryInterval * (failureCount * 1.2))
|
||||
|
||||
return min(maxRetryInterval, nextDelay)
|
||||
}
|
||||
|
||||
override func getSnodeForPolling(
|
||||
for publicKey: String,
|
||||
on queue: DispatchQueue
|
||||
) -> Promise<Snode> {
|
||||
if let targetSnode: Snode = self.targetSnode.wrappedValue {
|
||||
return Promise.value(targetSnode)
|
||||
}
|
||||
|
||||
// Used the cached swarm for the given key and update the list of unusedSnodes
|
||||
let swarm: Set<Snode> = (SnodeAPI.swarmCache.wrappedValue[publicKey] ?? [])
|
||||
let unusedSnodes: Set<Snode> = swarm.subtracting(usedSnodes.wrappedValue)
|
||||
|
||||
// randomElement() uses the system's default random generator, which is cryptographically secure
|
||||
if let nextSnode: Snode = unusedSnodes.randomElement() {
|
||||
self.targetSnode.mutate { $0 = nextSnode }
|
||||
self.usedSnodes.mutate { $0.insert(nextSnode) }
|
||||
|
||||
return Promise.value(nextSnode)
|
||||
}
|
||||
|
||||
// If we haven't retrieved a target snode at this point then either the cache
|
||||
// is empty or we have used all of the snodes and need to start from scratch
|
||||
return SnodeAPI.getSwarm(for: publicKey)
|
||||
.then(on: queue) { [weak self] _ -> Promise<Snode> in
|
||||
guard let strongSelf = self else { return Promise(error: SnodeAPIError.generic) }
|
||||
|
||||
self?.targetSnode.mutate { $0 = nil }
|
||||
self?.usedSnodes.mutate { $0.removeAll() }
|
||||
|
||||
return strongSelf.getSnodeForPolling(for: publicKey, on: queue)
|
||||
}
|
||||
}
|
||||
|
||||
override func handlePollError(_ error: Error, for publicKey: String) {
|
||||
if UserDefaults.sharedLokiProject?[.isMainAppActive] != true {
|
||||
// Do nothing when an error gets throws right after returning from the background (happens frequently)
|
||||
}
|
||||
else if let targetSnode: Snode = targetSnode.wrappedValue {
|
||||
SNLog("Polling \(targetSnode) failed; dropping it and switching to next snode.")
|
||||
self.targetSnode.mutate { $0 = nil }
|
||||
SnodeAPI.dropSnodeFromSwarmIfNeeded(targetSnode, publicKey: publicKey)
|
||||
}
|
||||
else {
|
||||
SNLog("Polling failed due to having no target service node.")
|
||||
}
|
||||
|
||||
// Try to restart the poller from scratch
|
||||
Threading.pollerQueue.async { [weak self] in
|
||||
self?.setUpPolling(for: publicKey)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
import Foundation
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import Sodium
|
||||
import SessionSnodeKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
#import "AppReadiness.h"
|
||||
#import "AppContext.h"
|
||||
#import <SignalCoreKit/SignalCoreKit.h>
|
||||
#import <SignalCoreKit/Threading.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -53,9 +51,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
DispatchMainThreadSafe(^{
|
||||
if ([NSThread isMainThread]) {
|
||||
[self.sharedManager runNowOrWhenAppWillBecomeReady:block];
|
||||
});
|
||||
}
|
||||
else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.sharedManager runNowOrWhenAppWillBecomeReady:block];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block
|
||||
|
@ -75,9 +78,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
+ (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
DispatchMainThreadSafe(^{
|
||||
if ([NSThread isMainThread]) {
|
||||
[self.sharedManager runNowOrWhenAppDidBecomeReady:block];
|
||||
});
|
||||
}
|
||||
else {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.sharedManager runNowOrWhenAppDidBecomeReady:block];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import SignalCoreKit
|
||||
|
||||
public extension OWSAES256Key {
|
||||
convenience init?(data: Data?) {
|
||||
guard let existingData: Data = data else { return nil }
|
||||
|
||||
self.init(data: existingData)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
import CryptoKit
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
|
@ -11,6 +12,9 @@ public struct ProfileManager {
|
|||
// Before encrypting and submitting we NULL pad the name data to this length.
|
||||
private static let nameDataLength: UInt = 64
|
||||
public static let maxAvatarDiameter: CGFloat = 640
|
||||
internal static let avatarAES256KeyByteLength: Int = 32
|
||||
private static let avatarNonceLength: Int = 12
|
||||
private static let avatarTagLength: Int = 16
|
||||
|
||||
private static var profileAvatarCache: Atomic<[String: Data]> = Atomic([:])
|
||||
private static var currentAvatarDownloads: Atomic<Set<String>> = Atomic([])
|
||||
|
@ -82,16 +86,40 @@ public struct ProfileManager {
|
|||
|
||||
// MARK: - Profile Encryption
|
||||
|
||||
private static func encryptProfileData(data: Data, key: OWSAES256Key) -> Data? {
|
||||
guard key.keyData.count == kAES256_KeyByteLength else { return nil }
|
||||
private static func encryptData(data: Data, key: Data) -> Data? {
|
||||
// The key structure is: nonce || ciphertext || authTag
|
||||
guard
|
||||
key.count == ProfileManager.avatarAES256KeyByteLength,
|
||||
let nonceData: Data = try? Randomness.generateRandomBytes(numberBytes: ProfileManager.avatarNonceLength),
|
||||
let nonce: AES.GCM.Nonce = try? AES.GCM.Nonce(data: nonceData),
|
||||
let sealedData: AES.GCM.SealedBox = try? AES.GCM.seal(
|
||||
data,
|
||||
using: SymmetricKey(data: key),
|
||||
nonce: nonce
|
||||
),
|
||||
let encryptedContent: Data = sealedData.combined
|
||||
else { return nil }
|
||||
|
||||
return Cryptography.encryptAESGCMProfileData(plainTextData: data, key: key)
|
||||
return encryptedContent
|
||||
}
|
||||
|
||||
private static func decryptProfileData(data: Data, key: OWSAES256Key) -> Data? {
|
||||
guard key.keyData.count == kAES256_KeyByteLength else { return nil }
|
||||
private static func decryptData(data: Data, key: Data) -> Data? {
|
||||
guard key.count == ProfileManager.avatarAES256KeyByteLength else { return nil }
|
||||
|
||||
return Cryptography.decryptAESGCMProfileData(encryptedData: data, key: key)
|
||||
// The key structure is: nonce || ciphertext || authTag
|
||||
let cipherTextLength: Int = (data.count - (ProfileManager.avatarNonceLength + ProfileManager.avatarTagLength))
|
||||
|
||||
guard
|
||||
cipherTextLength > 0,
|
||||
let sealedData: AES.GCM.SealedBox = try? AES.GCM.SealedBox(
|
||||
nonce: AES.GCM.Nonce(data: data.subdata(in: 0..<ProfileManager.avatarNonceLength)),
|
||||
ciphertext: data.subdata(in: ProfileManager.avatarNonceLength..<(ProfileManager.avatarNonceLength + cipherTextLength)),
|
||||
tag: data.subdata(in: (data.count - ProfileManager.avatarTagLength)..<data.count)
|
||||
),
|
||||
let decryptedData: Data = try? AES.GCM.open(sealedData, using: SymmetricKey(data: key))
|
||||
else { return nil }
|
||||
|
||||
return decryptedData
|
||||
}
|
||||
|
||||
// MARK: - File Paths
|
||||
|
@ -151,8 +179,8 @@ public struct ProfileManager {
|
|||
}
|
||||
guard
|
||||
let fileId: String = Attachment.fileId(for: profileUrlStringAtStart),
|
||||
let profileKeyAtStart: OWSAES256Key = profile.profileEncryptionKey,
|
||||
profileKeyAtStart.keyData.count > 0
|
||||
let profileKeyAtStart: Data = profile.profileEncryptionKey,
|
||||
profileKeyAtStart.count > 0
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
@ -178,8 +206,8 @@ public struct ProfileManager {
|
|||
}
|
||||
|
||||
guard
|
||||
let latestProfileKey: OWSAES256Key = latestProfile.profileEncryptionKey,
|
||||
!latestProfileKey.keyData.isEmpty,
|
||||
let latestProfileKey: Data = latestProfile.profileEncryptionKey,
|
||||
!latestProfileKey.isEmpty,
|
||||
latestProfileKey == profileKeyAtStart
|
||||
else {
|
||||
OWSLogger.warn("Ignoring avatar download for obsolete user profile.")
|
||||
|
@ -239,15 +267,85 @@ public struct ProfileManager {
|
|||
imageFilePath: String?,
|
||||
success: ((Database, Profile) throws -> ())? = nil,
|
||||
failure: ((ProfileManagerError) -> ())? = nil
|
||||
) {
|
||||
prepareAndUploadAvatarImage(
|
||||
queue: queue,
|
||||
image: image,
|
||||
imageFilePath: imageFilePath,
|
||||
success: { fileInfo, newProfileKey in
|
||||
// If we have no download url the we are removing the profile image
|
||||
guard let (downloadUrl, fileName): (String, String) = fileInfo else {
|
||||
Storage.shared.writeAsync { db in
|
||||
let existingProfile: Profile = Profile.fetchOrCreateCurrentUser(db)
|
||||
|
||||
OWSLogger.verbose(existingProfile.profilePictureUrl != nil ?
|
||||
"Updating local profile on service with cleared avatar." :
|
||||
"Updating local profile on service with no avatar."
|
||||
)
|
||||
|
||||
let updatedProfile: Profile = try existingProfile
|
||||
.with(
|
||||
name: profileName,
|
||||
profilePictureUrl: nil,
|
||||
profilePictureFileName: nil,
|
||||
profileEncryptionKey: (existingProfile.profilePictureUrl != nil ?
|
||||
.update(newProfileKey) :
|
||||
.existing
|
||||
)
|
||||
)
|
||||
.saved(db)
|
||||
|
||||
try SessionUtil.update(
|
||||
profile: updatedProfile,
|
||||
in: .global(variant: .userProfile)
|
||||
)
|
||||
|
||||
SNLog("Successfully updated service with profile.")
|
||||
try success?(db, updatedProfile)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Update user defaults
|
||||
UserDefaults.standard[.lastProfilePictureUpload] = Date()
|
||||
|
||||
// Update the profile
|
||||
Storage.shared.writeAsync { db in
|
||||
let profile: Profile = try Profile
|
||||
.fetchOrCreateCurrentUser(db)
|
||||
.with(
|
||||
name: profileName,
|
||||
profilePictureUrl: .update(downloadUrl),
|
||||
profilePictureFileName: .update(fileName),
|
||||
profileEncryptionKey: .update(newProfileKey)
|
||||
)
|
||||
.saved(db)
|
||||
|
||||
SNLog("Successfully updated service with profile.")
|
||||
try success?(db, profile)
|
||||
}
|
||||
},
|
||||
failure: failure
|
||||
)
|
||||
}
|
||||
|
||||
public static func prepareAndUploadAvatarImage(
|
||||
queue: DispatchQueue,
|
||||
image: UIImage?,
|
||||
imageFilePath: String?,
|
||||
success: @escaping ((downloadUrl: String, fileName: String)?, Data) -> (),
|
||||
failure: ((ProfileManagerError) -> ())? = nil
|
||||
) {
|
||||
queue.async {
|
||||
// If the profile avatar was updated or removed then encrypt with a new profile key
|
||||
// to ensure that other users know that our profile picture was updated
|
||||
let newProfileKey: OWSAES256Key = OWSAES256Key.generateRandom()
|
||||
let newProfileKey: Data
|
||||
let maxAvatarBytes: UInt = (5 * 1000 * 1000)
|
||||
let avatarImageData: Data?
|
||||
|
||||
do {
|
||||
newProfileKey = try Randomness.generateRandomBytes(numberBytes: ProfileManager.avatarAES256KeyByteLength)
|
||||
|
||||
avatarImageData = try {
|
||||
guard var image: UIImage = image else {
|
||||
guard let imageFilePath: String = imageFilePath else { return nil }
|
||||
|
|
|
@ -8,6 +8,7 @@ import BackgroundTasks
|
|||
import PromiseKit
|
||||
import SessionMessagingKit
|
||||
import SignalUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
public final class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
private var didPerformSetup = false
|
||||
|
@ -137,6 +138,9 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
|
|||
|
||||
self.handleSuccessForIncomingCall(db, for: callMessage)
|
||||
|
||||
case let sharedConfigMessage as SharedConfigMessage:
|
||||
try SessionUtil.handleConfigMessages(db, messages: [sharedConfigMessage])
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Availability.h>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/NSObject+OWS.h>
|
||||
#import <SessionUIKit/SessionUIKit.h>
|
||||
#endif
|
|
@ -6,9 +6,6 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
// Separate iOS Frameworks from other imports.
|
||||
#import <SignalCoreKit/NSObject+OWS.h>
|
||||
#import <SignalCoreKit/OWSAsserts.h>
|
||||
#import <SignalCoreKit/OWSLogs.h>
|
||||
#import <SignalUtilitiesKit/UIFont+OWS.h>
|
||||
#import <SessionUtilitiesKit/UIView+OWS.h>
|
||||
#import <SessionUtilitiesKit/AppContext.h>
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
import UIKit
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
import SignalUtilitiesKit
|
||||
import SessionUIKit
|
||||
import SessionUtilitiesKit
|
||||
import SignalCoreKit
|
||||
|
||||
final class SAEScreenLockViewController: ScreenLockViewController {
|
||||
private var hasShownAuthUIOnce: Bool = false
|
||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
|||
import SignalUtilitiesKit
|
||||
import SessionUtilitiesKit
|
||||
import SessionMessagingKit
|
||||
import SignalCoreKit
|
||||
|
||||
/// This is _NOT_ a singleton and will be instantiated each time that the SAE is used.
|
||||
final class ShareAppExtensionContext: NSObject, AppContext {
|
||||
|
|
|
@ -5,6 +5,7 @@ import CoreServices
|
|||
import PromiseKit
|
||||
import SignalUtilitiesKit
|
||||
import SessionUIKit
|
||||
import SignalCoreKit
|
||||
|
||||
final class ShareVC: UINavigationController, ShareViewDelegate {
|
||||
private var areVersionMigrationsComplete = false
|
||||
|
|
|
@ -4,7 +4,6 @@ import UIKit
|
|||
import GRDB
|
||||
import PromiseKit
|
||||
import DifferenceKit
|
||||
import Sodium
|
||||
import SessionUIKit
|
||||
import SignalUtilitiesKit
|
||||
import SessionMessagingKit
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import Foundation
|
||||
import GRDB
|
||||
import SignalCoreKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
public enum GetSnodePoolJob: JobExecutor {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension SnodeAPI {
|
||||
public class DeleteAllMessagesRequest: SnodeAuthenticatedRequestBody {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case namespace
|
||||
}
|
||||
|
||||
/// The message namespace from which to delete messages. The request will delete all messages
|
||||
/// from the specific namespace, or from all namespaces when not provided
|
||||
///
|
||||
/// **Note:** If omitted when sending the request, messages are deleted from the default namespace
|
||||
/// only (namespace 0)
|
||||
let namespace: SnodeAPI.Namespace?
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(
|
||||
namespace: SnodeAPI.Namespace?,
|
||||
pubkey: String,
|
||||
timestampMs: UInt64,
|
||||
ed25519PublicKey: [UInt8],
|
||||
ed25519SecretKey: [UInt8]
|
||||
) {
|
||||
self.namespace = namespace
|
||||
|
||||
super.init(
|
||||
pubkey: pubkey,
|
||||
ed25519PublicKey: ed25519PublicKey,
|
||||
ed25519SecretKey: ed25519SecretKey,
|
||||
timestampMs: timestampMs
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Coding
|
||||
|
||||
override public func encode(to encoder: Encoder) throws {
|
||||
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// If no namespace is specified it defaults to the default namespace only (namespace
|
||||
// 0), so instead in this case we want to explicitly delete from `all` namespaces
|
||||
switch namespace {
|
||||
case .some(let namespace): try container.encode(namespace, forKey: .namespace)
|
||||
case .none: try container.encode("all", forKey: .namespace)
|
||||
}
|
||||
|
||||
try super.encode(to: encoder)
|
||||
}
|
||||
|
||||
// MARK: - Abstract Methods
|
||||
|
||||
override func generateSignature() throws -> [UInt8] {
|
||||
/// Ed25519 signature of `( "delete_all" || namespace || timestamp )`, where
|
||||
/// `namespace` is the empty string for the default namespace (whether explicitly specified or
|
||||
/// not), and otherwise the stringified version of the namespace parameter (i.e. "99" or "-42" or "all").
|
||||
/// The signature must be signed by the ed25519 pubkey in `pubkey` (omitting the leading prefix).
|
||||
/// Must be base64 encoded for json requests; binary for OMQ requests.
|
||||
let verificationBytes: [UInt8] = SnodeAPI.Endpoint.deleteAll.rawValue.bytes
|
||||
.appending(
|
||||
contentsOf: (namespace == nil ?
|
||||
"all" :
|
||||
namespace?.verificationString
|
||||
)?.bytes
|
||||
)
|
||||
.appending(contentsOf: timestampMs.map { "\($0)" }?.data(using: .utf8)?.bytes)
|
||||
|
||||
guard
|
||||
let signatureBytes: [UInt8] = sodium.wrappedValue.sign.signature(
|
||||
message: verificationBytes,
|
||||
secretKey: ed25519SecretKey
|
||||
)
|
||||
else {
|
||||
throw SnodeAPIError.signingFailed
|
||||
}
|
||||
|
||||
return signatureBytes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension SnodeAPI {
|
||||
public class GetMessagesRequest: SnodeAuthenticatedRequestBody {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case lastHash = "last_hash"
|
||||
case namespace
|
||||
}
|
||||
|
||||
let lastHash: String
|
||||
let namespace: SnodeAPI.Namespace?
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(
|
||||
lastHash: String,
|
||||
namespace: SnodeAPI.Namespace?,
|
||||
pubkey: String,
|
||||
subkey: String?,
|
||||
timestampMs: UInt64,
|
||||
ed25519PublicKey: [UInt8],
|
||||
ed25519SecretKey: [UInt8]
|
||||
) {
|
||||
self.lastHash = lastHash
|
||||
self.namespace = namespace
|
||||
|
||||
super.init(
|
||||
pubkey: pubkey,
|
||||
ed25519PublicKey: ed25519PublicKey,
|
||||
ed25519SecretKey: ed25519SecretKey,
|
||||
subkey: subkey,
|
||||
timestampMs: timestampMs
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Coding
|
||||
|
||||
override public func encode(to encoder: Encoder) throws {
|
||||
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(lastHash, forKey: .lastHash)
|
||||
try container.encodeIfPresent(namespace, forKey: .namespace)
|
||||
|
||||
try super.encode(to: encoder)
|
||||
}
|
||||
|
||||
// MARK: - Abstract Methods
|
||||
|
||||
override func generateSignature() throws -> [UInt8] {
|
||||
/// Ed25519 signature of `("retrieve" || namespace || timestamp)` (if using a non-0
|
||||
/// namespace), or `("retrieve" || timestamp)` when fetching from the default namespace. Both
|
||||
/// namespace and timestamp are the base10 expressions of the relevant values. Must be base64
|
||||
/// encoded for json requests; binary for OMQ requests.
|
||||
let verificationBytes: [UInt8] = SnodeAPI.Endpoint.getMessages.rawValue.bytes
|
||||
.appending(contentsOf: namespace?.verificationString.bytes)
|
||||
.appending(contentsOf: timestampMs.map { "\($0)" }?.data(using: .utf8)?.bytes)
|
||||
|
||||
guard
|
||||
let signatureBytes: [UInt8] = sodium.wrappedValue.sign.signature(
|
||||
message: verificationBytes,
|
||||
secretKey: ed25519SecretKey
|
||||
)
|
||||
else {
|
||||
throw SnodeAPIError.signingFailed
|
||||
}
|
||||
|
||||
return signatureBytes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension SnodeAPI {
|
||||
public class SendMessageRequest: SnodeAuthenticatedRequestBody {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case namespace
|
||||
case signatureTimestamp = "sig_timestamp"
|
||||
}
|
||||
|
||||
let message: SnodeMessage
|
||||
let namespace: SnodeAPI.Namespace
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
public init(
|
||||
message: SnodeMessage,
|
||||
namespace: SnodeAPI.Namespace,
|
||||
subkey: String?,
|
||||
timestampMs: UInt64,
|
||||
ed25519PublicKey: [UInt8],
|
||||
ed25519SecretKey: [UInt8]
|
||||
) {
|
||||
self.message = message
|
||||
self.namespace = namespace
|
||||
|
||||
super.init(
|
||||
pubkey: message.recipient,
|
||||
ed25519PublicKey: ed25519PublicKey,
|
||||
ed25519SecretKey: ed25519SecretKey,
|
||||
subkey: subkey,
|
||||
timestampMs: timestampMs
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Coding
|
||||
|
||||
override public func encode(to encoder: Encoder) throws {
|
||||
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try super.encode(to: encoder)
|
||||
|
||||
/// **Note:** We **MUST** do the `message.encode` after we call `super.encode` because it will
|
||||
/// override the `timestampMs` value with the value in the message (if we do it the other way around then
|
||||
/// the the API call timestamp will be sent instead which is incorrect. For this specific request type we have a
|
||||
/// separate `signatureTimestamp` value to store the timestamp used to generate the signature
|
||||
try message.encode(to: encoder)
|
||||
try container.encode(namespace, forKey: .namespace)
|
||||
try container.encode(timestampMs, forKey: .signatureTimestamp)
|
||||
}
|
||||
|
||||
// MARK: - Abstract Methods
|
||||
|
||||
override func generateSignature() throws -> [UInt8] {
|
||||
/// Ed25519 signature of `("store" || namespace || sig_timestamp)`, where namespace and
|
||||
/// `sig_timestamp` are the base10 expression of the namespace and `sig_timestamp` values. Must be
|
||||
/// base64 encoded for json requests; binary for OMQ requests. For non-05 type pubkeys (i.e. non
|
||||
/// session ids) the signature will be verified using `pubkey`. For 05 pubkeys, see the following
|
||||
/// option.
|
||||
let verificationBytes: [UInt8] = SnodeAPI.Endpoint.sendMessage.rawValue.bytes
|
||||
.appending(contentsOf: namespace.verificationString.bytes)
|
||||
.appending(contentsOf: timestampMs.map { "\($0)" }?.data(using: .utf8)?.bytes)
|
||||
|
||||
guard
|
||||
let signatureBytes: [UInt8] = sodium.wrappedValue.sign.signature(
|
||||
message: verificationBytes,
|
||||
secretKey: ed25519SecretKey
|
||||
)
|
||||
else {
|
||||
throw SnodeAPIError.signingFailed
|
||||
}
|
||||
|
||||
return signatureBytes
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension SnodeAPI {
|
||||
enum Namespace: Int, Codable {
|
||||
case `default` = 0
|
||||
|
||||
case userProfileConfig = 2
|
||||
|
||||
case legacyClosedGroup = -10
|
||||
|
||||
// MARK: Variables
|
||||
|
||||
var requiresReadAuthentication: Bool {
|
||||
switch self {
|
||||
case .legacyClosedGroup: return false
|
||||
default: return true
|
||||
}
|
||||
}
|
||||
|
||||
var requiresWriteAuthentication: Bool {
|
||||
switch self {
|
||||
// Not in use until we can batch delete and store config messages
|
||||
case .default, .legacyClosedGroup: return false
|
||||
default: return true
|
||||
}
|
||||
}
|
||||
|
||||
var verificationString: String {
|
||||
switch self {
|
||||
case .`default`: return ""
|
||||
default: return "\(self.rawValue)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,12 @@ import Foundation
|
|||
import Combine
|
||||
import GRDB
|
||||
import PromiseKit
|
||||
import SignalCoreKit
|
||||
|
||||
open class Storage {
|
||||
private static let dbFileName: String = "Session.sqlite"
|
||||
private static let keychainService: String = "TSKeyChainService"
|
||||
private static let dbCipherKeySpecKey: String = "GRDBDatabaseCipherKeySpec"
|
||||
private static let kSQLCipherKeySpecLength: Int32 = 48
|
||||
private static let kSQLCipherKeySpecLength: Int = 48
|
||||
|
||||
private static var sharedDatabaseDirectoryPath: String { "\(OWSFileSystem.appSharedDataDirectoryPath())/database" }
|
||||
private static var databasePath: String { "\(Storage.sharedDatabaseDirectoryPath)/\(Storage.dbFileName)" }
|
||||
|
@ -103,7 +102,7 @@ open class Storage {
|
|||
migrations: [TargetMigrations],
|
||||
async: Bool = true,
|
||||
onProgressUpdate: ((CGFloat, TimeInterval) -> ())?,
|
||||
onComplete: @escaping (Swift.Result<Database, Error>, Bool) -> ()
|
||||
onComplete: @escaping (Swift.Result<Void, Error>, Bool) -> ()
|
||||
) {
|
||||
guard isValid, let dbWriter: DatabaseWriter = dbWriter else { return }
|
||||
|
||||
|
@ -179,7 +178,7 @@ open class Storage {
|
|||
}
|
||||
|
||||
// Store the logic to run when the migration completes
|
||||
let migrationCompleted: (Swift.Result<Database, Error>) -> () = { [weak self] result in
|
||||
let migrationCompleted: (Swift.Result<Void, Error>) -> () = { [weak self] result in
|
||||
self?.hasCompletedMigrations = true
|
||||
self?.migrationProgressUpdater = nil
|
||||
SUKLegacy.clearLegacyDatabaseInstance()
|
||||
|
@ -194,16 +193,23 @@ open class Storage {
|
|||
// Note: The non-async migration should only be used for unit tests
|
||||
guard async else {
|
||||
do { try self.migrator?.migrate(dbWriter) }
|
||||
catch {
|
||||
try? dbWriter.read { db in
|
||||
migrationCompleted(Swift.Result<Database, Error>.failure(error))
|
||||
}
|
||||
}
|
||||
catch { migrationCompleted(Swift.Result<Void, Error>.failure(error)) }
|
||||
return
|
||||
}
|
||||
|
||||
self.migrator?.asyncMigrate(dbWriter) { result in
|
||||
migrationCompleted(result)
|
||||
let finalResult: Swift.Result<Void, Error> = {
|
||||
switch result {
|
||||
case .failure(let error): return .failure(error)
|
||||
case .success: return .success(())
|
||||
}
|
||||
}()
|
||||
|
||||
// Note: We need to dispatch this to the next run toop to prevent any potential re-entrancy
|
||||
// issues since the 'asyncMigrate' returns a result containing a DB instance
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
migrationCompleted(finalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,7 +257,7 @@ open class Storage {
|
|||
case (_, errSecItemNotFound):
|
||||
// No keySpec was found so we need to generate a new one
|
||||
do {
|
||||
var keySpec: Data = Randomness.generateRandomBytes(kSQLCipherKeySpecLength)
|
||||
var keySpec: Data = try Randomness.generateRandomBytes(numberBytes: kSQLCipherKeySpecLength)
|
||||
defer { keySpec.resetBytes(in: 0..<keySpec.count) } // Reset content immediately after use
|
||||
|
||||
try SSKDefaultKeychainStorage.shared.set(data: keySpec, service: keychainService, key: dbCipherKeySpecKey)
|
||||
|
|
|
@ -43,6 +43,12 @@ public class Atomic<Value> {
|
|||
return mutation(&value)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func mutate<T>(_ mutation: (inout Value) throws -> T) throws -> T {
|
||||
return try queue.sync {
|
||||
return try mutation(&value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Atomic where Value: CustomDebugStringConvertible {
|
||||
|
|
|
@ -20,6 +20,7 @@ public enum General {
|
|||
|
||||
public enum GeneralError: Error {
|
||||
case keyGenerationFailed
|
||||
case randomGenerationFailed
|
||||
}
|
||||
|
||||
public func getUserHexEncodedPublicKey(_ db: Database? = nil, dependencies: Dependencies = Dependencies()) -> String {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue