mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Started work on updated SOGS support
Split the OpenGroupAPIV2 into separate files Started working on the new auth and blinded-id approaches (new auth working with un-blinded id suggesting blinded-id code is incorrect) Updated the SOGS request/response types to use Codable Updated the SOGS Request type to use enums instead of strings for keys (to reduce likelihood of typos breaking things) Updated SessionMessagingKit to use Codable and JSONEncoder/JSONDecoder instead of the legacy JSONSerialization Cleaned up some naming conventions in the SessionMessagingKit (calling a URLRequest body 'parameters' is very confusing...) Removed the custom TSRequest class (just using standard URLRequest everywhere instead) Added a number of extension functions to enable some more functional-coding styles Added extensions to Sodium methods to allow scalar multiplication and the ability to hash providing a salt and a personalisation value (both needed for new SOGS auth) Fixed an issue where the legacy auth for SOGS could crash due to threading issues (multiple threads accessing the same variable) Fixed an issue where if you were in two rooms in a single SOGS and deleted one of them, the other room would stop getting updates as the server public key was getting removed
This commit is contained in:
parent
49dd52a1fb
commit
2284375fc0
55 changed files with 1927 additions and 721 deletions
|
@ -196,7 +196,7 @@
|
||||||
B8569AC325CB5D2900DBA3DB /* ConversationVC+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AC225CB5D2900DBA3DB /* ConversationVC+Interaction.swift */; };
|
B8569AC325CB5D2900DBA3DB /* ConversationVC+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AC225CB5D2900DBA3DB /* ConversationVC+Interaction.swift */; };
|
||||||
B8569AD325CBA13D00DBA3DB /* MediaTextOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AD225CBA13D00DBA3DB /* MediaTextOverlayView.swift */; };
|
B8569AD325CBA13D00DBA3DB /* MediaTextOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AD225CBA13D00DBA3DB /* MediaTextOverlayView.swift */; };
|
||||||
B8569AE325CBB19A00DBA3DB /* DocumentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AE225CBB19A00DBA3DB /* DocumentView.swift */; };
|
B8569AE325CBB19A00DBA3DB /* DocumentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AE225CBB19A00DBA3DB /* DocumentView.swift */; };
|
||||||
B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Conversion.swift */; };
|
B866CE112581C1A900535CC4 /* Sodium+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E7134E251C867C009649BB /* Sodium+Utilities.swift */; };
|
||||||
B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; };
|
B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; };
|
||||||
B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; };
|
B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; };
|
||||||
B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */; };
|
B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8758859264503A6000E60D0 /* JoinOpenGroupModal.swift */; };
|
||||||
|
@ -238,7 +238,7 @@
|
||||||
B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; };
|
B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */; };
|
||||||
B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; };
|
B894D0752339EDCF00B4D94D /* NukeDataModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B894D0742339EDCF00B4D94D /* NukeDataModal.swift */; };
|
||||||
B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */; };
|
B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */; };
|
||||||
B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */; };
|
B8AE75A425A6C6A6001A84D2 /* Data+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AE75A325A6C6A6001A84D2 /* Data+Utilities.swift */; };
|
||||||
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */; };
|
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */; };
|
||||||
B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
B8AE761425ABFBB9001A84D2 /* GeneralUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AF4BB326A5204600583500 /* SendSeedModal.swift */; };
|
B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8AF4BB326A5204600583500 /* SendSeedModal.swift */; };
|
||||||
|
@ -300,7 +300,6 @@
|
||||||
C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; };
|
C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; };
|
||||||
C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */; };
|
C31D1DE9252172D4005D4DA8 /* ContactUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */; };
|
||||||
C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */; };
|
C31FFE57254A5FFE00F19441 /* KeyPairUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */; };
|
||||||
C3227FF6260AAD66006EA627 /* OpenGroupMessageV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3227FF5260AAD66006EA627 /* OpenGroupMessageV2.swift */; };
|
|
||||||
C32824D325C9F9790062D0A7 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
|
C32824D325C9F9790062D0A7 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
|
||||||
C328250F25CA06020062D0A7 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328250E25CA06020062D0A7 /* VoiceMessageView.swift */; };
|
C328250F25CA06020062D0A7 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328250E25CA06020062D0A7 /* VoiceMessageView.swift */; };
|
||||||
C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328251E25CA3A900062D0A7 /* QuoteView.swift */; };
|
C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328251E25CA3A900062D0A7 /* QuoteView.swift */; };
|
||||||
|
@ -510,8 +509,6 @@
|
||||||
C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */ = {isa = PBXBuildFile; fileRef = C352A3762557859C00338F3E /* NSTimer+Proxying.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
C352A3772557864000338F3E /* NSTimer+Proxying.h in Headers */ = {isa = PBXBuildFile; fileRef = C352A3762557859C00338F3E /* NSTimer+Proxying.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
C352A3892557876500338F3E /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A3882557876500338F3E /* JobQueue.swift */; };
|
C352A3892557876500338F3E /* JobQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A3882557876500338F3E /* JobQueue.swift */; };
|
||||||
C352A3932557883D00338F3E /* JobDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A3922557883D00338F3E /* JobDelegate.swift */; };
|
C352A3932557883D00338F3E /* JobDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C352A3922557883D00338F3E /* JobDelegate.swift */; };
|
||||||
C352A3A62557B60D00338F3E /* TSRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C352A3A52557B60D00338F3E /* TSRequest.m */; };
|
|
||||||
C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C352A3A42557B5F000338F3E /* TSRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
|
||||||
C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; };
|
C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; };
|
||||||
C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; };
|
C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; };
|
||||||
C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C354E75923FE2A7600CE22E3 /* BaseVC.swift */; };
|
C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C354E75923FE2A7600CE22E3 /* BaseVC.swift */; };
|
||||||
|
@ -676,7 +673,7 @@
|
||||||
C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */; };
|
C3A7219A2558C1660043A11F /* AnyPromise+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A721992558C1660043A11F /* AnyPromise+Conversion.swift */; };
|
||||||
C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */; };
|
C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A7225D2558C38D0043A11F /* Promise+Retaining.swift */; };
|
||||||
C3A76A8D25DB83F90074CB90 /* PermissionMissingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A76A8C25DB83F90074CB90 /* PermissionMissingModal.swift */; };
|
C3A76A8D25DB83F90074CB90 /* PermissionMissingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A76A8C25DB83F90074CB90 /* PermissionMissingModal.swift */; };
|
||||||
C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Description.swift */; };
|
C3AABDDF2553ECF00042FF4C /* Array+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Utilities.swift */; };
|
||||||
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AAFFF125AE99710089E6DD /* AppDelegate.swift */; };
|
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3AAFFF125AE99710089E6DD /* AppDelegate.swift */; };
|
||||||
C3ADC66126426688005F1414 /* ShareVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ADC66026426688005F1414 /* ShareVC.swift */; };
|
C3ADC66126426688005F1414 /* ShareVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3ADC66026426688005F1414 /* ShareVC.swift */; };
|
||||||
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
|
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0752554CDA60050F1E3 /* Configuration.swift */; };
|
||||||
|
@ -684,7 +681,7 @@
|
||||||
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; };
|
C3BBE0A72554D4DE0050F1E3 /* Promise+Retrying.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */; };
|
||||||
C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D92553860B00C340D1 /* JSON.swift */; };
|
C3BBE0A82554D4DE0050F1E3 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D92553860B00C340D1 /* JSON.swift */; };
|
||||||
C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BC255385EE00C340D1 /* HTTP.swift */; };
|
C3BBE0A92554D4DE0050F1E3 /* HTTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5BC255385EE00C340D1 /* HTTP.swift */; };
|
||||||
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */; };
|
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D52553860A00C340D1 /* Dictionary+Utilities.swift */; };
|
||||||
C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */; };
|
C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0B42554F0E10050F1E3 /* ProofOfWork.swift */; };
|
||||||
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */; };
|
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3BBE0C62554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift */; };
|
||||||
C3C2A5A3255385C100C340D1 /* SessionSnodeKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
C3C2A5A3255385C100C340D1 /* SessionSnodeKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C3C2A5A1255385C100C340D1 /* SessionSnodeKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
@ -754,7 +751,6 @@
|
||||||
C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; };
|
C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF1255A580500E217F9 /* OWSThumbnailService.swift */; };
|
||||||
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */; };
|
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */; };
|
||||||
C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; };
|
C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; };
|
||||||
C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */; };
|
|
||||||
C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */; };
|
C3DB66AC260ACA42001EFC55 /* OpenGroupManagerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */; };
|
||||||
C3DB66C3260ACCE6001EFC55 /* OpenGroupPollerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */; };
|
C3DB66C3260ACCE6001EFC55 /* OpenGroupPollerV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */; };
|
||||||
C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */; };
|
C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */; };
|
||||||
|
@ -778,6 +774,8 @@
|
||||||
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
|
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
|
||||||
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */; };
|
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */; };
|
||||||
FD5D201E27B0D87C00FEA984 /* IdPrefix.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */; };
|
FD5D201E27B0D87C00FEA984 /* IdPrefix.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */; };
|
||||||
|
FD5D202027B0E67900FEA984 /* String+Encoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D201F27B0E67800FEA984 /* String+Encoding.swift */; };
|
||||||
|
FD5D202227B1D74F00FEA984 /* ECKeyPair+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D202127B1D74F00FEA984 /* ECKeyPair+Conversion.swift */; };
|
||||||
FD659AC027A7649600F12C02 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */; };
|
FD659AC027A7649600F12C02 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */; };
|
||||||
FD705A8C278CDB5600F16121 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */; };
|
FD705A8C278CDB5600F16121 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */; };
|
||||||
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8D278CE29800F16121 /* String+Localization.swift */; };
|
FD705A8E278CE29800F16121 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A8D278CE29800F16121 /* String+Localization.swift */; };
|
||||||
|
@ -787,6 +785,33 @@
|
||||||
FD705A98278E9F4D00F16121 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */; };
|
FD705A98278E9F4D00F16121 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A97278E9F4D00F16121 /* UIColor+Extensions.swift */; };
|
||||||
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
|
FD88BAD927A7439C00BBC442 /* MessageRequestsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */; };
|
||||||
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
|
FD88BADB27A750F200BBC442 /* MessageRequestsMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */; };
|
||||||
|
FDC4380927B31D4E00C60D73 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4380827B31D4E00C60D73 /* Error.swift */; };
|
||||||
|
FDC4380B27B31D7E00C60D73 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4380A27B31D7E00C60D73 /* Request.swift */; };
|
||||||
|
FDC4381527B329CE00C60D73 /* NonceGenerator16Byte.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381427B329CE00C60D73 /* NonceGenerator16Byte.swift */; };
|
||||||
|
FDC4381727B32EC700C60D73 /* Personalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381627B32EC700C60D73 /* Personalization.swift */; };
|
||||||
|
FDC4381A27B34EBA00C60D73 /* CompactPollBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381927B34EBA00C60D73 /* CompactPollBody.swift */; };
|
||||||
|
FDC4381C27B354AC00C60D73 /* PublicKeyBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381B27B354AC00C60D73 /* PublicKeyBody.swift */; };
|
||||||
|
FDC4382027B36ADC00C60D73 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381F27B36ADC00C60D73 /* Endpoint.swift */; };
|
||||||
|
FDC4382627B37F6900C60D73 /* DeletedMessagesResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382527B37F6900C60D73 /* DeletedMessagesResponse.swift */; };
|
||||||
|
FDC4382827B37FD300C60D73 /* ModeratorsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382727B37FD300C60D73 /* ModeratorsResponse.swift */; };
|
||||||
|
FDC4382A27B3802D00C60D73 /* RoomsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382927B3802D00C60D73 /* RoomsResponse.swift */; };
|
||||||
|
FDC4382C27B380E300C60D73 /* MemberCountResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382B27B380E300C60D73 /* MemberCountResponse.swift */; };
|
||||||
|
FDC4382F27B383AF00C60D73 /* UnregisterResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */; };
|
||||||
|
FDC4383127B3841C00C60D73 /* RegisterResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383027B3841C00C60D73 /* RegisterResponse.swift */; };
|
||||||
|
FDC4383827B3863200C60D73 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383727B3863200C60D73 /* VersionResponse.swift */; };
|
||||||
|
FDC4383A27B4696200C60D73 /* AuthTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383927B4696200C60D73 /* AuthTokenResponse.swift */; };
|
||||||
|
FDC4383E27B4708600C60D73 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383D27B4708600C60D73 /* Atomic.swift */; };
|
||||||
|
FDC4384027B4746D00C60D73 /* GetInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383F27B4746D00C60D73 /* GetInfoResponse.swift */; };
|
||||||
|
FDC4384727B47F4D00C60D73 /* OpenGroupMessageV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384327B47F4D00C60D73 /* OpenGroupMessageV2.swift */; };
|
||||||
|
FDC4384827B47F4D00C60D73 /* RoomInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384427B47F4D00C60D73 /* RoomInfo.swift */; };
|
||||||
|
FDC4384927B47F4D00C60D73 /* CompactPollResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384527B47F4D00C60D73 /* CompactPollResponse.swift */; };
|
||||||
|
FDC4384A27B47F4D00C60D73 /* Deletion.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384627B47F4D00C60D73 /* Deletion.swift */; };
|
||||||
|
FDC4384C27B47F7700C60D73 /* OpenGroupV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384B27B47F7700C60D73 /* OpenGroupV2.swift */; };
|
||||||
|
FDC4384F27B4804F00C60D73 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384E27B4804F00C60D73 /* Header.swift */; };
|
||||||
|
FDC4385127B4807400C60D73 /* QueryParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385027B4807400C60D73 /* QueryParam.swift */; };
|
||||||
|
FDC4385727B484B700C60D73 /* FileUploadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385627B484B700C60D73 /* FileUploadResponse.swift */; };
|
||||||
|
FDC4385927B484E800C60D73 /* FileUploadBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385827B484E800C60D73 /* FileUploadBody.swift */; };
|
||||||
|
FDC4385B27B485DE00C60D73 /* FileDownloadResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385A27B485DE00C60D73 /* FileDownloadResponse.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -1236,7 +1261,7 @@
|
||||||
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = "<group>"; };
|
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanQRCodeWrapperVC.swift; sourceTree = "<group>"; };
|
||||||
B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = "<group>"; };
|
B894D0742339EDCF00B4D94D /* NukeDataModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NukeDataModal.swift; sourceTree = "<group>"; };
|
||||||
B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = "<group>"; };
|
B897621B25D201F7004F83B2 /* ScrollToBottomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToBottomButton.swift; sourceTree = "<group>"; };
|
||||||
B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Trimming.swift"; sourceTree = "<group>"; };
|
B8AE75A325A6C6A6001A84D2 /* Data+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Utilities.swift"; sourceTree = "<group>"; };
|
||||||
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneralUtilities.h; sourceTree = "<group>"; };
|
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneralUtilities.h; sourceTree = "<group>"; };
|
||||||
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneralUtilities.m; sourceTree = "<group>"; };
|
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneralUtilities.m; sourceTree = "<group>"; };
|
||||||
B8AF4BB326A5204600583500 /* SendSeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendSeedModal.swift; sourceTree = "<group>"; };
|
B8AF4BB326A5204600583500 /* SendSeedModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendSeedModal.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1314,7 +1339,6 @@
|
||||||
C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSelectionVC.swift; sourceTree = "<group>"; };
|
C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSelectionVC.swift; sourceTree = "<group>"; };
|
||||||
C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUtilities.swift; sourceTree = "<group>"; };
|
C31D1DE8252172D4005D4DA8 /* ContactUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUtilities.swift; sourceTree = "<group>"; };
|
||||||
C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairUtilities.swift; sourceTree = "<group>"; };
|
C31FFE56254A5FFE00F19441 /* KeyPairUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPairUtilities.swift; sourceTree = "<group>"; };
|
||||||
C3227FF5260AAD66006EA627 /* OpenGroupMessageV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupMessageV2.swift; sourceTree = "<group>"; };
|
|
||||||
C328250E25CA06020062D0A7 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = "<group>"; };
|
C328250E25CA06020062D0A7 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = "<group>"; };
|
||||||
C328251E25CA3A900062D0A7 /* QuoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteView.swift; sourceTree = "<group>"; };
|
C328251E25CA3A900062D0A7 /* QuoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteView.swift; sourceTree = "<group>"; };
|
||||||
C328252F25CA55360062D0A7 /* ContextMenuWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuWindow.swift; sourceTree = "<group>"; };
|
C328252F25CA55360062D0A7 /* ContextMenuWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuWindow.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1525,8 +1549,6 @@
|
||||||
C352A3762557859C00338F3E /* NSTimer+Proxying.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Proxying.h"; sourceTree = "<group>"; };
|
C352A3762557859C00338F3E /* NSTimer+Proxying.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Proxying.h"; sourceTree = "<group>"; };
|
||||||
C352A3882557876500338F3E /* JobQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobQueue.swift; sourceTree = "<group>"; };
|
C352A3882557876500338F3E /* JobQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobQueue.swift; sourceTree = "<group>"; };
|
||||||
C352A3922557883D00338F3E /* JobDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobDelegate.swift; sourceTree = "<group>"; };
|
C352A3922557883D00338F3E /* JobDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobDelegate.swift; sourceTree = "<group>"; };
|
||||||
C352A3A42557B5F000338F3E /* TSRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TSRequest.h; sourceTree = "<group>"; };
|
|
||||||
C352A3A52557B60D00338F3E /* TSRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSRequest.m; sourceTree = "<group>"; };
|
|
||||||
C353F8F8244809150011121A /* PNOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNOptionView.swift; sourceTree = "<group>"; };
|
C353F8F8244809150011121A /* PNOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNOptionView.swift; sourceTree = "<group>"; };
|
||||||
C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = "<group>"; };
|
C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = "<group>"; };
|
||||||
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = "<group>"; };
|
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1731,11 +1753,11 @@
|
||||||
C3C2A5CE2553860700C340D1 /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
C3C2A5CE2553860700C340D1 /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
||||||
C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Hashing.swift"; sourceTree = "<group>"; };
|
C3C2A5CF2553860700C340D1 /* Promise+Hashing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Hashing.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D02553860800C340D1 /* Promise+Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Threading.swift"; sourceTree = "<group>"; };
|
C3C2A5D02553860800C340D1 /* Promise+Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Threading.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D12553860800C340D1 /* Array+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Description.swift"; sourceTree = "<group>"; };
|
C3C2A5D12553860800C340D1 /* Array+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Utilities.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D22553860900C340D1 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = "<group>"; };
|
C3C2A5D22553860900C340D1 /* String+Trimming.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Trimming.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Delaying.swift"; sourceTree = "<group>"; };
|
C3C2A5D32553860900C340D1 /* Promise+Delaying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Delaying.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D42553860A00C340D1 /* Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
C3C2A5D42553860A00C340D1 /* Threading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
||||||
C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Description.swift"; sourceTree = "<group>"; };
|
C3C2A5D52553860A00C340D1 /* Dictionary+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Utilities.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Retrying.swift"; sourceTree = "<group>"; };
|
C3C2A5D62553860B00C340D1 /* Promise+Retrying.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Promise+Retrying.swift"; sourceTree = "<group>"; };
|
||||||
C3C2A5D72553860B00C340D1 /* AESGCM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESGCM.swift; sourceTree = "<group>"; };
|
C3C2A5D72553860B00C340D1 /* AESGCM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESGCM.swift; sourceTree = "<group>"; };
|
||||||
C3C2A5D82553860B00C340D1 /* Data+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Utilities.swift"; sourceTree = "<group>"; };
|
C3C2A5D82553860B00C340D1 /* Data+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Utilities.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1767,13 +1789,12 @@
|
||||||
C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
C3D9E43025676D3D0040E4F3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
|
||||||
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationMessage.swift; sourceTree = "<group>"; };
|
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationMessage.swift; sourceTree = "<group>"; };
|
||||||
C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = "<group>"; };
|
C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = "<group>"; };
|
||||||
C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupV2.swift; sourceTree = "<group>"; };
|
|
||||||
C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupManagerV2.swift; sourceTree = "<group>"; };
|
C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupManagerV2.swift; sourceTree = "<group>"; };
|
||||||
C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupPollerV2.swift; sourceTree = "<group>"; };
|
C3DB66C2260ACCE6001EFC55 /* OpenGroupPollerV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupPollerV2.swift; sourceTree = "<group>"; };
|
||||||
C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupAPIV2+ObjC.swift"; sourceTree = "<group>"; };
|
C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupAPIV2+ObjC.swift"; sourceTree = "<group>"; };
|
||||||
C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
|
C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
|
||||||
C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = "<group>"; };
|
C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = "<group>"; };
|
||||||
C3E7134E251C867C009649BB /* Sodium+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Conversion.swift"; sourceTree = "<group>"; };
|
C3E7134E251C867C009649BB /* Sodium+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sodium+Utilities.swift"; sourceTree = "<group>"; };
|
||||||
C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
|
||||||
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
|
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
|
||||||
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
|
@ -1813,6 +1834,8 @@
|
||||||
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
|
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
|
||||||
FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
|
FD5D201027AA331F00FEA984 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
|
||||||
FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdPrefix.swift; sourceTree = "<group>"; };
|
FD5D201D27B0D87C00FEA984 /* IdPrefix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdPrefix.swift; sourceTree = "<group>"; };
|
||||||
|
FD5D201F27B0E67800FEA984 /* String+Encoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Encoding.swift"; sourceTree = "<group>"; };
|
||||||
|
FD5D202127B1D74F00FEA984 /* ECKeyPair+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ECKeyPair+Conversion.swift"; sourceTree = "<group>"; };
|
||||||
FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
|
FD659ABF27A7649600F12C02 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
|
||||||
FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
|
FD705A8B278CDB5600F16121 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
|
||||||
FD705A8D278CE29800F16121 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
FD705A8D278CE29800F16121 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1823,6 +1846,33 @@
|
||||||
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
|
FD88BAD827A7439C00BBC442 /* MessageRequestsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsCell.swift; sourceTree = "<group>"; };
|
||||||
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
|
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestsMigration.swift; sourceTree = "<group>"; };
|
||||||
FD9039443F7CB729CF71350E /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
FD9039443F7CB729CF71350E /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
FDC4380827B31D4E00C60D73 /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4380A27B31D7E00C60D73 /* Request.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4381427B329CE00C60D73 /* NonceGenerator16Byte.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonceGenerator16Byte.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4381627B32EC700C60D73 /* Personalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Personalization.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4381927B34EBA00C60D73 /* CompactPollBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactPollBody.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4381B27B354AC00C60D73 /* PublicKeyBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKeyBody.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4381F27B36ADC00C60D73 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4382527B37F6900C60D73 /* DeletedMessagesResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedMessagesResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4382727B37FD300C60D73 /* ModeratorsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModeratorsResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4382927B3802D00C60D73 /* RoomsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomsResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4382B27B380E300C60D73 /* MemberCountResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberCountResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnregisterResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4383027B3841C00C60D73 /* RegisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4383727B3863200C60D73 /* VersionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4383927B4696200C60D73 /* AuthTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthTokenResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4383D27B4708600C60D73 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4383F27B4746D00C60D73 /* GetInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetInfoResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384327B47F4D00C60D73 /* OpenGroupMessageV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupMessageV2.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384427B47F4D00C60D73 /* RoomInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomInfo.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384527B47F4D00C60D73 /* CompactPollResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompactPollResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384627B47F4D00C60D73 /* Deletion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deletion.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384B27B47F7700C60D73 /* OpenGroupV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupV2.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4384E27B4804F00C60D73 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4385027B4807400C60D73 /* QueryParam.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryParam.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4385627B484B700C60D73 /* FileUploadResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadResponse.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4385827B484E800C60D73 /* FileUploadBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadBody.swift; sourceTree = "<group>"; };
|
||||||
|
FDC4385A27B485DE00C60D73 /* FileDownloadResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDownloadResponse.swift; sourceTree = "<group>"; };
|
||||||
FEDBAE1B98C49BBE8C87F575 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
|
FEDBAE1B98C49BBE8C87F575 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
FF9BA33D021B115B1F5B4E46 /* Pods-SessionMessagingKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionMessagingKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionMessagingKit/Pods-SessionMessagingKit.app store release.xcconfig"; sourceTree = "<group>"; };
|
FF9BA33D021B115B1F5B4E46 /* Pods-SessionMessagingKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionMessagingKit.app store release.xcconfig"; path = "Pods/Target Support Files/Pods-SessionMessagingKit/Pods-SessionMessagingKit.app store release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
@ -2303,8 +2353,6 @@
|
||||||
B8FF8EA525C11FEF004D1F22 /* IPv4.swift */,
|
B8FF8EA525C11FEF004D1F22 /* IPv4.swift */,
|
||||||
C3C2A5D92553860B00C340D1 /* JSON.swift */,
|
C3C2A5D92553860B00C340D1 /* JSON.swift */,
|
||||||
C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */,
|
C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */,
|
||||||
C352A3A42557B5F000338F3E /* TSRequest.h */,
|
|
||||||
C352A3A52557B60D00338F3E /* TSRequest.m */,
|
|
||||||
);
|
);
|
||||||
path = Networking;
|
path = Networking;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -2330,11 +2378,11 @@
|
||||||
children = (
|
children = (
|
||||||
C33FDB8A255A581200E217F9 /* AppContext.h */,
|
C33FDB8A255A581200E217F9 /* AppContext.h */,
|
||||||
C33FDB85255A581100E217F9 /* AppContext.m */,
|
C33FDB85255A581100E217F9 /* AppContext.m */,
|
||||||
C3C2A5D12553860800C340D1 /* Array+Description.swift */,
|
C3C2A5D12553860800C340D1 /* Array+Utilities.swift */,
|
||||||
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */,
|
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */,
|
||||||
B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */,
|
B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */,
|
||||||
B8AE75A325A6C6A6001A84D2 /* Data+Trimming.swift */,
|
B8AE75A325A6C6A6001A84D2 /* Data+Utilities.swift */,
|
||||||
C3C2A5D52553860A00C340D1 /* Dictionary+Description.swift */,
|
C3C2A5D52553860A00C340D1 /* Dictionary+Utilities.swift */,
|
||||||
B87EF18026377A1D00124B3C /* Features.swift */,
|
B87EF18026377A1D00124B3C /* Features.swift */,
|
||||||
B8BC00BF257D90E30032E807 /* General.swift */,
|
B8BC00BF257D90E30032E807 /* General.swift */,
|
||||||
C3C2A5CE2553860700C340D1 /* Logging.swift */,
|
C3C2A5CE2553860700C340D1 /* Logging.swift */,
|
||||||
|
@ -2357,6 +2405,7 @@
|
||||||
C33FDB3F255A580C00E217F9 /* String+SSK.swift */,
|
C33FDB3F255A580C00E217F9 /* String+SSK.swift */,
|
||||||
C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */,
|
C3C2AC2D2553CBEB00C340D1 /* String+Trimming.swift */,
|
||||||
FD705A8D278CE29800F16121 /* String+Localization.swift */,
|
FD705A8D278CE29800F16121 /* String+Localization.swift */,
|
||||||
|
FD5D201F27B0E67800FEA984 /* String+Encoding.swift */,
|
||||||
C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */,
|
C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */,
|
||||||
C35D0DB425AE5F1200B6BF49 /* UIEdgeInsets.swift */,
|
C35D0DB425AE5F1200B6BF49 /* UIEdgeInsets.swift */,
|
||||||
FD705A91278D051200F16121 /* ReusableView.swift */,
|
FD705A91278D051200F16121 /* ReusableView.swift */,
|
||||||
|
@ -3043,6 +3092,7 @@
|
||||||
C379DC6825672B5E0002D4EB /* Notifications */ = {
|
C379DC6825672B5E0002D4EB /* Notifications */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FDC4382D27B383A600C60D73 /* Models */,
|
||||||
C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */,
|
C33FDB7A255A581000E217F9 /* NotificationsProtocol.h */,
|
||||||
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */,
|
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */,
|
||||||
);
|
);
|
||||||
|
@ -3182,11 +3232,11 @@
|
||||||
C3A721332558BDDF0043A11F /* Open Groups */ = {
|
C3A721332558BDDF0043A11F /* Open Groups */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C3DB6694260AC923001EFC55 /* OpenGroupV2.swift */,
|
FDC4381827B34EAD00C60D73 /* Models */,
|
||||||
|
FDC4380727B31D3A00C60D73 /* Types */,
|
||||||
B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */,
|
B88FA7B726045D100049422F /* OpenGroupAPIV2.swift */,
|
||||||
C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */,
|
C3DB66CB260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift */,
|
||||||
C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */,
|
C3DB66AB260ACA42001EFC55 /* OpenGroupManagerV2.swift */,
|
||||||
C3227FF5260AAD66006EA627 /* OpenGroupMessageV2.swift */,
|
|
||||||
);
|
);
|
||||||
path = "Open Groups";
|
path = "Open Groups";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -3194,6 +3244,7 @@
|
||||||
C3A7215C2558C0AC0043A11F /* File Server */ = {
|
C3A7215C2558C0AC0043A11F /* File Server */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FDC4383227B385B200C60D73 /* Models */,
|
||||||
B87EF17026367CF800124B3C /* FileServerAPIV2.swift */,
|
B87EF17026367CF800124B3C /* FileServerAPIV2.swift */,
|
||||||
);
|
);
|
||||||
path = "File Server";
|
path = "File Server";
|
||||||
|
@ -3204,6 +3255,7 @@
|
||||||
children = (
|
children = (
|
||||||
C33FDB01255A580700E217F9 /* AppReadiness.h */,
|
C33FDB01255A580700E217F9 /* AppReadiness.h */,
|
||||||
C33FDB75255A581000E217F9 /* AppReadiness.m */,
|
C33FDB75255A581000E217F9 /* AppReadiness.m */,
|
||||||
|
FDC4383D27B4708600C60D73 /* Atomic.swift */,
|
||||||
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */,
|
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */,
|
||||||
C37F53E8255BA9BB002AEA92 /* Environment.h */,
|
C37F53E8255BA9BB002AEA92 /* Environment.h */,
|
||||||
C37F5402255BA9ED002AEA92 /* Environment.m */,
|
C37F5402255BA9ED002AEA92 /* Environment.m */,
|
||||||
|
@ -3241,7 +3293,8 @@
|
||||||
C33FDB91255A581200E217F9 /* ProtoUtils.h */,
|
C33FDB91255A581200E217F9 /* ProtoUtils.h */,
|
||||||
C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */,
|
C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */,
|
||||||
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */,
|
C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */,
|
||||||
C3E7134E251C867C009649BB /* Sodium+Conversion.swift */,
|
C3E7134E251C867C009649BB /* Sodium+Utilities.swift */,
|
||||||
|
FD5D202127B1D74F00FEA984 /* ECKeyPair+Conversion.swift */,
|
||||||
C33FDB31255A580A00E217F9 /* SSKEnvironment.h */,
|
C33FDB31255A580A00E217F9 /* SSKEnvironment.h */,
|
||||||
C33FDAF4255A580600E217F9 /* SSKEnvironment.m */,
|
C33FDAF4255A580600E217F9 /* SSKEnvironment.m */,
|
||||||
C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */,
|
C33FDB32255A580A00E217F9 /* SSKIncrementingIdFinder.swift */,
|
||||||
|
@ -3329,6 +3382,7 @@
|
||||||
C32C5BB9256DC7C4003C73A2 /* To Do */,
|
C32C5BB9256DC7C4003C73A2 /* To Do */,
|
||||||
C3BBE0752554CDA60050F1E3 /* Configuration.swift */,
|
C3BBE0752554CDA60050F1E3 /* Configuration.swift */,
|
||||||
C3BBE07F2554CDD70050F1E3 /* Storage.swift */,
|
C3BBE07F2554CDD70050F1E3 /* Storage.swift */,
|
||||||
|
FDC4384D27B47FD600C60D73 /* Common Networking */,
|
||||||
B8B3201F258B1A540020074B /* Contacts */,
|
B8B3201F258B1A540020074B /* Contacts */,
|
||||||
C32C5BCB256DC818003C73A2 /* Database */,
|
C32C5BCB256DC818003C73A2 /* Database */,
|
||||||
C300A5BB2554AFFB00555489 /* Messages */,
|
C300A5BB2554AFFB00555489 /* Messages */,
|
||||||
|
@ -3636,6 +3690,75 @@
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
FDC4380727B31D3A00C60D73 /* Types */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4380A27B31D7E00C60D73 /* Request.swift */,
|
||||||
|
FDC4381F27B36ADC00C60D73 /* Endpoint.swift */,
|
||||||
|
FDC4380827B31D4E00C60D73 /* Error.swift */,
|
||||||
|
FDC4381627B32EC700C60D73 /* Personalization.swift */,
|
||||||
|
FDC4381427B329CE00C60D73 /* NonceGenerator16Byte.swift */,
|
||||||
|
);
|
||||||
|
path = Types;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FDC4381827B34EAD00C60D73 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4384B27B47F7700C60D73 /* OpenGroupV2.swift */,
|
||||||
|
FDC4381B27B354AC00C60D73 /* PublicKeyBody.swift */,
|
||||||
|
FDC4381927B34EBA00C60D73 /* CompactPollBody.swift */,
|
||||||
|
FDC4384527B47F4D00C60D73 /* CompactPollResponse.swift */,
|
||||||
|
FDC4383F27B4746D00C60D73 /* GetInfoResponse.swift */,
|
||||||
|
FDC4382927B3802D00C60D73 /* RoomsResponse.swift */,
|
||||||
|
FDC4384427B47F4D00C60D73 /* RoomInfo.swift */,
|
||||||
|
FDC4382B27B380E300C60D73 /* MemberCountResponse.swift */,
|
||||||
|
FDC4384327B47F4D00C60D73 /* OpenGroupMessageV2.swift */,
|
||||||
|
FDC4382527B37F6900C60D73 /* DeletedMessagesResponse.swift */,
|
||||||
|
FDC4384627B47F4D00C60D73 /* Deletion.swift */,
|
||||||
|
FDC4382727B37FD300C60D73 /* ModeratorsResponse.swift */,
|
||||||
|
FDC4383927B4696200C60D73 /* AuthTokenResponse.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FDC4382D27B383A600C60D73 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */,
|
||||||
|
FDC4383027B3841C00C60D73 /* RegisterResponse.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FDC4383227B385B200C60D73 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4383727B3863200C60D73 /* VersionResponse.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FDC4384D27B47FD600C60D73 /* Common Networking */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4385527B484AE00C60D73 /* Models */,
|
||||||
|
FDC4384E27B4804F00C60D73 /* Header.swift */,
|
||||||
|
FDC4385027B4807400C60D73 /* QueryParam.swift */,
|
||||||
|
);
|
||||||
|
path = "Common Networking";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FDC4385527B484AE00C60D73 /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FDC4385827B484E800C60D73 /* FileUploadBody.swift */,
|
||||||
|
FDC4385627B484B700C60D73 /* FileUploadResponse.swift */,
|
||||||
|
FDC4385A27B485DE00C60D73 /* FileDownloadResponse.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
@ -3723,7 +3846,6 @@
|
||||||
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */,
|
C3D9E3FA25676BCE0040E4F3 /* TSYapDatabaseObject.h in Headers */,
|
||||||
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */,
|
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */,
|
||||||
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */,
|
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */,
|
||||||
C352A3B72557B6ED00338F3E /* TSRequest.h in Headers */,
|
|
||||||
C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */,
|
C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */,
|
||||||
C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */,
|
C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */,
|
||||||
C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */,
|
C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */,
|
||||||
|
@ -4635,7 +4757,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
C3AABDDF2553ECF00042FF4C /* Array+Description.swift in Sources */,
|
C3AABDDF2553ECF00042FF4C /* Array+Utilities.swift in Sources */,
|
||||||
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */,
|
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */,
|
||||||
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */,
|
C3D9E41525676C320040E4F3 /* Storage.swift in Sources */,
|
||||||
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */,
|
C32C5D83256DD5B6003C73A2 /* SSKKeychainStorage.swift in Sources */,
|
||||||
|
@ -4654,17 +4776,17 @@
|
||||||
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */,
|
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */,
|
||||||
C32C5FA1256DFED5003C73A2 /* NSArray+Functional.m in Sources */,
|
C32C5FA1256DFED5003C73A2 /* NSArray+Functional.m in Sources */,
|
||||||
C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */,
|
C3A7225E2558C38D0043A11F /* Promise+Retaining.swift in Sources */,
|
||||||
|
FD5D202027B0E67900FEA984 /* String+Encoding.swift in Sources */,
|
||||||
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */,
|
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */,
|
||||||
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Description.swift in Sources */,
|
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Utilities.swift in Sources */,
|
||||||
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
|
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
|
||||||
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */,
|
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */,
|
||||||
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
|
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
|
||||||
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
|
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
|
||||||
C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */,
|
C32C5B48256DC211003C73A2 /* NSNotificationCenter+OWS.m in Sources */,
|
||||||
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */,
|
C3D9E3C925676AF30040E4F3 /* TSYapDatabaseObject.m in Sources */,
|
||||||
C352A3A62557B60D00338F3E /* TSRequest.m in Sources */,
|
|
||||||
FD705A92278D051200F16121 /* ReusableView.swift in Sources */,
|
FD705A92278D051200F16121 /* ReusableView.swift in Sources */,
|
||||||
B8AE75A425A6C6A6001A84D2 /* Data+Trimming.swift in Sources */,
|
B8AE75A425A6C6A6001A84D2 /* Data+Utilities.swift in Sources */,
|
||||||
B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */,
|
B8856DE6256F15F2001CE70E /* String+SSK.swift in Sources */,
|
||||||
C3471ED42555386B00297E91 /* AESGCM.swift in Sources */,
|
C3471ED42555386B00297E91 /* AESGCM.swift in Sources */,
|
||||||
C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */,
|
C32C5DDB256DD9FF003C73A2 /* ContentProxy.swift in Sources */,
|
||||||
|
@ -4699,6 +4821,7 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */,
|
B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */,
|
||||||
|
FDC4382A27B3802D00C60D73 /* RoomsResponse.swift in Sources */,
|
||||||
C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */,
|
C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */,
|
||||||
C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */,
|
C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */,
|
||||||
C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */,
|
C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */,
|
||||||
|
@ -4711,6 +4834,7 @@
|
||||||
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */,
|
FD5D201127AA331F00FEA984 /* ConfigurationMessage+Convenience.swift in Sources */,
|
||||||
C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */,
|
C32C5A13256DB7A5003C73A2 /* PushNotificationAPI.swift in Sources */,
|
||||||
C32A026325A801AA000ED5D4 /* NSData+messagePadding.m in Sources */,
|
C32A026325A801AA000ED5D4 /* NSData+messagePadding.m in Sources */,
|
||||||
|
FDC4384927B47F4D00C60D73 /* CompactPollResponse.swift in Sources */,
|
||||||
C352A3932557883D00338F3E /* JobDelegate.swift in Sources */,
|
C352A3932557883D00338F3E /* JobDelegate.swift in Sources */,
|
||||||
C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */,
|
C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */,
|
||||||
C3A3A108256E1A5C004D228D /* OWSIncomingMessageFinder.m in Sources */,
|
C3A3A108256E1A5C004D228D /* OWSIncomingMessageFinder.m in Sources */,
|
||||||
|
@ -4718,17 +4842,20 @@
|
||||||
C32C5BDD256DC88D003C73A2 /* OWSReadReceiptManager.m in Sources */,
|
C32C5BDD256DC88D003C73A2 /* OWSReadReceiptManager.m in Sources */,
|
||||||
C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */,
|
C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */,
|
||||||
C3C2A7562553A3AB00C340D1 /* VisibleMessage+Quote.swift in Sources */,
|
C3C2A7562553A3AB00C340D1 /* VisibleMessage+Quote.swift in Sources */,
|
||||||
C3227FF6260AAD66006EA627 /* OpenGroupMessageV2.swift in Sources */,
|
|
||||||
B8B32021258B1A650020074B /* Contact.swift in Sources */,
|
B8B32021258B1A650020074B /* Contact.swift in Sources */,
|
||||||
|
FDC4380B27B31D7E00C60D73 /* Request.swift in Sources */,
|
||||||
|
FDC4384027B4746D00C60D73 /* GetInfoResponse.swift in Sources */,
|
||||||
C32C5C89256DD0D2003C73A2 /* Storage+Jobs.swift in Sources */,
|
C32C5C89256DD0D2003C73A2 /* Storage+Jobs.swift in Sources */,
|
||||||
C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */,
|
C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */,
|
||||||
7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */,
|
7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */,
|
||||||
|
FDC4383E27B4708600C60D73 /* Atomic.swift in Sources */,
|
||||||
C32C5A76256DBBCF003C73A2 /* SignalAttachment.swift in Sources */,
|
C32C5A76256DBBCF003C73A2 /* SignalAttachment.swift in Sources */,
|
||||||
C32C5CA4256DD1DC003C73A2 /* TSAccountManager.m in Sources */,
|
C32C5CA4256DD1DC003C73A2 /* TSAccountManager.m in Sources */,
|
||||||
C352A3892557876500338F3E /* JobQueue.swift in Sources */,
|
C352A3892557876500338F3E /* JobQueue.swift in Sources */,
|
||||||
C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */,
|
C3BBE0B52554F0E10050F1E3 /* ProofOfWork.swift in Sources */,
|
||||||
C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */,
|
C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */,
|
||||||
C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */,
|
C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */,
|
||||||
|
FDC4381A27B34EBA00C60D73 /* CompactPollBody.swift in Sources */,
|
||||||
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */,
|
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */,
|
||||||
C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */,
|
C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */,
|
||||||
C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */,
|
C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */,
|
||||||
|
@ -4751,41 +4878,56 @@
|
||||||
B8F5F60325EDE16F003BF8D4 /* DataExtractionNotification.swift in Sources */,
|
B8F5F60325EDE16F003BF8D4 /* DataExtractionNotification.swift in Sources */,
|
||||||
C32C5D24256DD4C0003C73A2 /* MentionsManager.swift in Sources */,
|
C32C5D24256DD4C0003C73A2 /* MentionsManager.swift in Sources */,
|
||||||
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */,
|
C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */,
|
||||||
|
FDC4384A27B47F4D00C60D73 /* Deletion.swift in Sources */,
|
||||||
C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */,
|
C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */,
|
||||||
B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */,
|
B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */,
|
||||||
|
FDC4382827B37FD300C60D73 /* ModeratorsResponse.swift in Sources */,
|
||||||
C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */,
|
C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */,
|
||||||
B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */,
|
B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */,
|
||||||
|
FD5D202227B1D74F00FEA984 /* ECKeyPair+Conversion.swift in Sources */,
|
||||||
|
FDC4381C27B354AC00C60D73 /* PublicKeyBody.swift in Sources */,
|
||||||
|
FDC4382F27B383AF00C60D73 /* UnregisterResponse.swift in Sources */,
|
||||||
C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */,
|
C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */,
|
||||||
C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */,
|
C32C5D19256DD493003C73A2 /* OWSLinkPreview.swift in Sources */,
|
||||||
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */,
|
C32C5CF0256DD3E4003C73A2 /* Storage+Shared.swift in Sources */,
|
||||||
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */,
|
C300A5BD2554B00D00555489 /* ReadReceipt.swift in Sources */,
|
||||||
C32C5AB5256DBE8F003C73A2 /* TSOutgoingMessage+Conversion.swift in Sources */,
|
C32C5AB5256DBE8F003C73A2 /* TSOutgoingMessage+Conversion.swift in Sources */,
|
||||||
|
FDC4385927B484E800C60D73 /* FileUploadBody.swift in Sources */,
|
||||||
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */,
|
C32C5E5B256DDF45003C73A2 /* OWSStorage.m in Sources */,
|
||||||
C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */,
|
C32C5E15256DDC78003C73A2 /* SSKPreferences.swift in Sources */,
|
||||||
C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */,
|
C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */,
|
||||||
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */,
|
B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */,
|
||||||
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */,
|
C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */,
|
||||||
|
FDC4384727B47F4D00C60D73 /* OpenGroupMessageV2.swift in Sources */,
|
||||||
|
FDC4384F27B4804F00C60D73 /* Header.swift in Sources */,
|
||||||
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */,
|
C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */,
|
||||||
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */,
|
B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */,
|
||||||
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */,
|
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */,
|
||||||
|
FDC4381727B32EC700C60D73 /* Personalization.swift in Sources */,
|
||||||
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */,
|
C32C5EDC256DF501003C73A2 /* YapDatabaseConnection+OWS.m in Sources */,
|
||||||
|
FDC4381527B329CE00C60D73 /* NonceGenerator16Byte.swift in Sources */,
|
||||||
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */,
|
C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */,
|
||||||
C35D76DB26606304009AA5FB /* ThreadUpdateBatcher.swift in Sources */,
|
C35D76DB26606304009AA5FB /* ThreadUpdateBatcher.swift in Sources */,
|
||||||
|
FDC4382C27B380E300C60D73 /* MemberCountResponse.swift in Sources */,
|
||||||
B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */,
|
B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */,
|
||||||
B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */,
|
B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */,
|
||||||
C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */,
|
C3D9E3BE25676AD70040E4F3 /* TSAttachmentPointer.m in Sources */,
|
||||||
C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */,
|
C3ECBF7B257056B700EA7FCE /* Threading.swift in Sources */,
|
||||||
C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */,
|
C32C5AAB256DBE8F003C73A2 /* TSIncomingMessage+Conversion.swift in Sources */,
|
||||||
B866CE112581C1A900535CC4 /* Sodium+Conversion.swift in Sources */,
|
B866CE112581C1A900535CC4 /* Sodium+Utilities.swift in Sources */,
|
||||||
C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */,
|
C32C5A88256DBCF9003C73A2 /* MessageReceiver+Handling.swift in Sources */,
|
||||||
C32C5C1B256DC9E0003C73A2 /* General.swift in Sources */,
|
C32C5C1B256DC9E0003C73A2 /* General.swift in Sources */,
|
||||||
C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */,
|
C32C5A02256DB658003C73A2 /* MessageSender+Convenience.swift in Sources */,
|
||||||
B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */,
|
B8566C6C256F60F50045A0B9 /* OWSUserProfile.m in Sources */,
|
||||||
B8D0A25925E367AC00C1835E /* Notification+MessageReceiver.swift in Sources */,
|
B8D0A25925E367AC00C1835E /* Notification+MessageReceiver.swift in Sources */,
|
||||||
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */,
|
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */,
|
||||||
|
FDC4380927B31D4E00C60D73 /* Error.swift in Sources */,
|
||||||
|
FDC4382027B36ADC00C60D73 /* Endpoint.swift in Sources */,
|
||||||
C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */,
|
C3DB66CC260AF1F3001EFC55 /* OpenGroupAPIV2+ObjC.swift in Sources */,
|
||||||
C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */,
|
C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */,
|
||||||
C34A977425A3E34A00852C71 /* ClosedGroupControlMessage.swift in Sources */,
|
C34A977425A3E34A00852C71 /* ClosedGroupControlMessage.swift in Sources */,
|
||||||
|
FDC4384C27B47F7700C60D73 /* OpenGroupV2.swift in Sources */,
|
||||||
|
FDC4382627B37F6900C60D73 /* DeletedMessagesResponse.swift in Sources */,
|
||||||
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */,
|
B88FA7B826045D100049422F /* OpenGroupAPIV2.swift in Sources */,
|
||||||
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */,
|
C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */,
|
||||||
C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */,
|
C32C5EB9256DE130003C73A2 /* OWSQuotedReplyModel+Conversion.swift in Sources */,
|
||||||
|
@ -4793,17 +4935,18 @@
|
||||||
B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */,
|
B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */,
|
||||||
C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */,
|
C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */,
|
||||||
C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */,
|
C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */,
|
||||||
|
FDC4383A27B4696200C60D73 /* AuthTokenResponse.swift in Sources */,
|
||||||
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */,
|
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */,
|
||||||
C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */,
|
C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */,
|
||||||
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */,
|
C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */,
|
||||||
C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */,
|
C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */,
|
||||||
C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */,
|
C32C5B1C256DC19D003C73A2 /* TSQuotedMessage.m in Sources */,
|
||||||
C3DB6695260AC923001EFC55 /* OpenGroupV2.swift in Sources */,
|
|
||||||
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
|
C352A349255781F400338F3E /* AttachmentDownloadJob.swift in Sources */,
|
||||||
C352A30925574D8500338F3E /* Message+Destination.swift in Sources */,
|
C352A30925574D8500338F3E /* Message+Destination.swift in Sources */,
|
||||||
C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */,
|
C300A5E72554B07300555489 /* ExpirationTimerUpdate.swift in Sources */,
|
||||||
B88A1AC725C90A4700E6D421 /* TypingIndicatorInteraction.swift in Sources */,
|
B88A1AC725C90A4700E6D421 /* TypingIndicatorInteraction.swift in Sources */,
|
||||||
C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */,
|
C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */,
|
||||||
|
FDC4384827B47F4D00C60D73 /* RoomInfo.swift in Sources */,
|
||||||
C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */,
|
C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */,
|
||||||
C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */,
|
C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */,
|
||||||
B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */,
|
B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */,
|
||||||
|
@ -4824,16 +4967,21 @@
|
||||||
C32C5D23256DD4C0003C73A2 /* Mention.swift in Sources */,
|
C32C5D23256DD4C0003C73A2 /* Mention.swift in Sources */,
|
||||||
C32C5FD6256E0346003C73A2 /* Notification+Thread.swift in Sources */,
|
C32C5FD6256E0346003C73A2 /* Notification+Thread.swift in Sources */,
|
||||||
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */,
|
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */,
|
||||||
|
FDC4383827B3863200C60D73 /* VersionResponse.swift in Sources */,
|
||||||
C32C5C88256DD0D2003C73A2 /* Storage+Messaging.swift in Sources */,
|
C32C5C88256DD0D2003C73A2 /* Storage+Messaging.swift in Sources */,
|
||||||
C32C59C7256DB41F003C73A2 /* TSThread.m in Sources */,
|
C32C59C7256DB41F003C73A2 /* TSThread.m in Sources */,
|
||||||
C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */,
|
C300A5B22554AF9800555489 /* VisibleMessage+Profile.swift in Sources */,
|
||||||
C32C5A75256DBBCF003C73A2 /* TSAttachmentPointer+Conversion.swift in Sources */,
|
C32C5A75256DBBCF003C73A2 /* TSAttachmentPointer+Conversion.swift in Sources */,
|
||||||
C32C5AF8256DC051003C73A2 /* OWSDisappearingMessagesConfiguration.m in Sources */,
|
C32C5AF8256DC051003C73A2 /* OWSDisappearingMessagesConfiguration.m in Sources */,
|
||||||
C32C5EBA256DE130003C73A2 /* OWSQuotedReplyModel.m in Sources */,
|
C32C5EBA256DE130003C73A2 /* OWSQuotedReplyModel.m in Sources */,
|
||||||
|
FDC4385127B4807400C60D73 /* QueryParam.swift in Sources */,
|
||||||
C32C5B62256DC333003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */,
|
C32C5B62256DC333003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.m in Sources */,
|
||||||
C352A2F525574B4700338F3E /* Job.swift in Sources */,
|
C352A2F525574B4700338F3E /* Job.swift in Sources */,
|
||||||
|
FDC4385727B484B700C60D73 /* FileUploadResponse.swift in Sources */,
|
||||||
|
FDC4385B27B485DE00C60D73 /* FileDownloadResponse.swift in Sources */,
|
||||||
C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */,
|
C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */,
|
||||||
C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */,
|
C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */,
|
||||||
|
FDC4383127B3841C00C60D73 /* RegisterResponse.swift in Sources */,
|
||||||
C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */,
|
C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */,
|
||||||
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */,
|
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -238,7 +238,7 @@ private final class EnterURLVC : UIViewController, UIGestureRecognizerDelegate,
|
||||||
return !suggestionGrid.frame.contains(location)
|
return !suggestionGrid.frame.contains(location)
|
||||||
}
|
}
|
||||||
|
|
||||||
func join(_ room: OpenGroupAPIV2.Info) {
|
func join(_ room: OpenGroupAPIV2.RoomInfo) {
|
||||||
joinOpenGroupVC.joinV2OpenGroup(room: room.id, server: OpenGroupAPIV2.defaultServer, publicKey: OpenGroupAPIV2.defaultServerPublicKey)
|
joinOpenGroupVC.joinV2OpenGroup(room: room.id, server: OpenGroupAPIV2.defaultServer, publicKey: OpenGroupAPIV2.defaultServerPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import NVActivityIndicatorView
|
||||||
|
|
||||||
final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||||
private let maxWidth: CGFloat
|
private let maxWidth: CGFloat
|
||||||
private var rooms: [OpenGroupAPIV2.Info] = [] { didSet { update() } }
|
private var rooms: [OpenGroupAPIV2.RoomInfo] = [] { didSet { update() } }
|
||||||
private var heightConstraint: NSLayoutConstraint!
|
private var heightConstraint: NSLayoutConstraint!
|
||||||
var delegate: OpenGroupSuggestionGridDelegate?
|
var delegate: OpenGroupSuggestionGridDelegate?
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ final class OpenGroupSuggestionGrid : UIView, UICollectionViewDataSource, UIColl
|
||||||
extension OpenGroupSuggestionGrid {
|
extension OpenGroupSuggestionGrid {
|
||||||
|
|
||||||
fileprivate final class Cell : UICollectionViewCell {
|
fileprivate final class Cell : UICollectionViewCell {
|
||||||
var room: OpenGroupAPIV2.Info? { didSet { update() } }
|
var room: OpenGroupAPIV2.RoomInfo? { didSet { update() } }
|
||||||
|
|
||||||
static let identifier = "OpenGroupSuggestionGridCell"
|
static let identifier = "OpenGroupSuggestionGridCell"
|
||||||
|
|
||||||
|
@ -183,5 +183,5 @@ extension OpenGroupSuggestionGrid {
|
||||||
// MARK: Delegate
|
// MARK: Delegate
|
||||||
protocol OpenGroupSuggestionGridDelegate {
|
protocol OpenGroupSuggestionGridDelegate {
|
||||||
|
|
||||||
func join(_ room: OpenGroupAPIV2.Info)
|
func join(_ room: OpenGroupAPIV2.RoomInfo)
|
||||||
}
|
}
|
||||||
|
|
23
SessionMessagingKit/Common Networking/Header.swift
Normal file
23
SessionMessagingKit/Common Networking/Header.swift
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum Header: String {
|
||||||
|
case authorization = "Authorization"
|
||||||
|
case contentType = "Content-Type"
|
||||||
|
|
||||||
|
case room = "Room" // TODO: Confirm this is needed
|
||||||
|
|
||||||
|
case sogsPubKey = "X-SOGS-Pubkey"
|
||||||
|
case sogsNonce = "X-SOGS-Nonce"
|
||||||
|
case sogsTimestamp = "X-SOGS-Timestamp"
|
||||||
|
case sogsHash = "X-SOGS-Hash"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Convenience
|
||||||
|
|
||||||
|
extension Dictionary where Key == Header, Value == String {
|
||||||
|
func toHTTPHeaders() -> [String: String] {
|
||||||
|
return self.reduce(into: [:]) { result, next in result[next.key.rawValue] = next.value }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct FileDownloadResponse: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case base64EncodedData = "result"
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: Data
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
try container.encode(data.base64EncodedString(), forKey: .base64EncodedData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Decoder
|
||||||
|
|
||||||
|
extension FileDownloadResponse {
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
let base64EncodedData: String = try container.decode(String.self, forKey: .base64EncodedData)
|
||||||
|
|
||||||
|
guard let data = Data(base64Encoded: base64EncodedData) else {
|
||||||
|
throw FileServerAPIV2.Error.parsingFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
self = FileDownloadResponse(
|
||||||
|
data: data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct FileUploadBody: Codable {
|
||||||
|
let file: String
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct FileUploadResponse: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case fileId = "result"
|
||||||
|
}
|
||||||
|
|
||||||
|
public let fileId: UInt64
|
||||||
|
}
|
8
SessionMessagingKit/Common Networking/QueryParam.swift
Normal file
8
SessionMessagingKit/Common Networking/QueryParam.swift
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum QueryParam: String {
|
||||||
|
case publicKey = "public_key"
|
||||||
|
case fromServerId = "from_server_id"
|
||||||
|
}
|
|
@ -22,16 +22,16 @@ public final class FileServerAPIV2 : NSObject {
|
||||||
private override init() { }
|
private override init() { }
|
||||||
|
|
||||||
// MARK: Error
|
// MARK: Error
|
||||||
public enum Error : LocalizedError {
|
public enum Error: LocalizedError {
|
||||||
case parsingFailed
|
case parsingFailed
|
||||||
case invalidURL
|
case invalidURL
|
||||||
case maxFileSizeExceeded
|
case maxFileSizeExceeded
|
||||||
|
|
||||||
public var errorDescription: String? {
|
public var errorDescription: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .parsingFailed: return "Invalid response."
|
case .parsingFailed: return "Invalid response."
|
||||||
case .invalidURL: return "Invalid URL."
|
case .invalidURL: return "Invalid URL."
|
||||||
case .maxFileSizeExceeded: return "Maximum file size exceeded."
|
case .maxFileSizeExceeded: return "Maximum file size exceeded."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,49 +40,61 @@ public final class FileServerAPIV2 : NSObject {
|
||||||
private struct Request {
|
private struct Request {
|
||||||
let verb: HTTP.Verb
|
let verb: HTTP.Verb
|
||||||
let endpoint: String
|
let endpoint: String
|
||||||
let queryParameters: [String:String]
|
let queryParameters: [QueryParam: String]
|
||||||
let parameters: JSON
|
let body: Data?
|
||||||
let headers: [String:String]
|
let headers: [Header: String]
|
||||||
/// Always `true` under normal circumstances. You might want to disable
|
/// Always `true` under normal circumstances. You might want to disable
|
||||||
/// this when running over Lokinet.
|
/// this when running over Lokinet.
|
||||||
let useOnionRouting: Bool
|
let useOnionRouting: Bool
|
||||||
|
|
||||||
init(verb: HTTP.Verb, endpoint: String, queryParameters: [String:String] = [:], parameters: JSON = [:],
|
init(verb: HTTP.Verb, endpoint: String, queryParameters: [QueryParam: String] = [:], body: Data? = nil,
|
||||||
headers: [String:String] = [:], useOnionRouting: Bool = true) {
|
headers: [Header: String] = [:], useOnionRouting: Bool = true) {
|
||||||
self.verb = verb
|
self.verb = verb
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
self.queryParameters = queryParameters
|
self.queryParameters = queryParameters
|
||||||
self.parameters = parameters
|
self.body = body
|
||||||
self.headers = headers
|
self.headers = headers
|
||||||
self.useOnionRouting = useOnionRouting
|
self.useOnionRouting = useOnionRouting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Convenience
|
// MARK: - Convenience
|
||||||
private static func send(_ request: Request, useOldServer: Bool) -> Promise<JSON> {
|
|
||||||
|
private static func send(_ request: Request, useOldServer: Bool) -> Promise<Data> {
|
||||||
let server = useOldServer ? oldServer : server
|
let server = useOldServer ? oldServer : server
|
||||||
let serverPublicKey = useOldServer ? oldServerPublicKey : serverPublicKey
|
let serverPublicKey = useOldServer ? oldServerPublicKey : serverPublicKey
|
||||||
let tsRequest: TSRequest
|
var urlRequest: URLRequest
|
||||||
|
// TODO: Combine this 'Request' with the the pattern in OpenGroupServerV2?
|
||||||
switch request.verb {
|
switch request.verb {
|
||||||
case .get:
|
case .get:
|
||||||
var rawURL = "\(server)/\(request.endpoint)"
|
var rawURL = "\(server)/\(request.endpoint)"
|
||||||
if !request.queryParameters.isEmpty {
|
|
||||||
let queryString = request.queryParameters.map { key, value in "\(key)=\(value)" }.joined(separator: "&")
|
if !request.queryParameters.isEmpty {
|
||||||
rawURL += "?\(queryString)"
|
let queryString = request.queryParameters.map { key, value in "\(key)=\(value)" }.joined(separator: "&")
|
||||||
}
|
rawURL += "?\(queryString)"
|
||||||
guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) }
|
}
|
||||||
tsRequest = TSRequest(url: url)
|
|
||||||
case .post, .put, .delete:
|
guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) }
|
||||||
let rawURL = "\(server)/\(request.endpoint)"
|
|
||||||
guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) }
|
urlRequest = URLRequest(url: url)
|
||||||
tsRequest = TSRequest(url: url, method: request.verb.rawValue, parameters: request.parameters)
|
|
||||||
|
case .post, .put, .delete:
|
||||||
|
let rawURL = "\(server)/\(request.endpoint)"
|
||||||
|
|
||||||
|
guard let url = URL(string: rawURL) else { return Promise(error: Error.invalidURL) }
|
||||||
|
|
||||||
|
urlRequest = URLRequest(url: url)
|
||||||
|
urlRequest.httpMethod = request.verb.rawValue
|
||||||
|
urlRequest.httpBody = request.body
|
||||||
}
|
}
|
||||||
tsRequest.allHTTPHeaderFields = request.headers
|
|
||||||
if request.useOnionRouting {
|
urlRequest.allHTTPHeaderFields = request.headers.toHTTPHeaders()
|
||||||
return OnionRequestAPI.sendOnionRequest(tsRequest, to: server, using: serverPublicKey)
|
|
||||||
} else {
|
guard request.useOnionRouting else {
|
||||||
preconditionFailure("It's currently not allowed to send non onion routed requests.")
|
preconditionFailure("It's currently not allowed to send non onion routed requests.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OnionRequestAPI.sendOnionRequest(urlRequest, to: server, using: serverPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: File Storage
|
// MARK: File Storage
|
||||||
|
@ -92,12 +104,17 @@ public final class FileServerAPIV2 : NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func upload(_ file: Data) -> Promise<UInt64> {
|
public static func upload(_ file: Data) -> Promise<UInt64> {
|
||||||
let base64EncodedFile = file.base64EncodedString()
|
let requestBody: FileUploadBody = FileUploadBody(file: file.base64EncodedString())
|
||||||
let parameters = [ "file" : base64EncodedFile ]
|
|
||||||
let request = Request(verb: .post, endpoint: "files", parameters: parameters)
|
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
|
||||||
return send(request, useOldServer: false).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
|
return Promise(error: HTTP.Error.invalidJSON)
|
||||||
guard let fileID = json["result"] as? UInt64 else { throw Error.parsingFailed }
|
}
|
||||||
return fileID
|
|
||||||
|
let request = Request(verb: .post, endpoint: "files", body: body)
|
||||||
|
return send(request, useOldServer: false).map(on: DispatchQueue.global(qos: .userInitiated)) { data in
|
||||||
|
let response: FileUploadResponse = try data.decoded(as: FileUploadResponse.self, customError: Error.parsingFailed)
|
||||||
|
|
||||||
|
return response.fileId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,17 +126,21 @@ public final class FileServerAPIV2 : NSObject {
|
||||||
|
|
||||||
public static func download(_ file: UInt64, useOldServer: Bool) -> Promise<Data> {
|
public static func download(_ file: UInt64, useOldServer: Bool) -> Promise<Data> {
|
||||||
let request = Request(verb: .get, endpoint: "files/\(file)")
|
let request = Request(verb: .get, endpoint: "files/\(file)")
|
||||||
return send(request, useOldServer: useOldServer).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
|
|
||||||
guard let base64EncodedFile = json["result"] as? String, let file = Data(base64Encoded: base64EncodedFile) else { throw Error.parsingFailed }
|
return send(request, useOldServer: useOldServer).map(on: DispatchQueue.global(qos: .userInitiated)) { data in
|
||||||
return file
|
let response: FileDownloadResponse = try data.decoded(as: FileDownloadResponse.self, customError: Error.parsingFailed)
|
||||||
|
|
||||||
|
return response.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getVersion(_ platform: String) -> Promise<String> {
|
public static func getVersion(_ platform: String) -> Promise<String> {
|
||||||
let request = Request(verb: .get, endpoint: "session_version?platform=\(platform)")
|
let request = Request(verb: .get, endpoint: "session_version?platform=\(platform)")
|
||||||
return send(request, useOldServer: false).map(on: DispatchQueue.global(qos: .userInitiated)) { json in
|
|
||||||
guard let version = json["result"] as? String else { throw Error.parsingFailed }
|
return send(request, useOldServer: false).map(on: DispatchQueue.global(qos: .userInitiated)) { data in
|
||||||
return version
|
let response: VersionResponse = try data.decoded(as: VersionResponse.self, customError: Error.parsingFailed)
|
||||||
|
|
||||||
|
return response.version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
SessionMessagingKit/File Server/Models/VersionResponse.swift
Normal file
13
SessionMessagingKit/File Server/Models/VersionResponse.swift
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension FileServerAPIV2 {
|
||||||
|
struct VersionResponse: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case version = "version"
|
||||||
|
}
|
||||||
|
|
||||||
|
public let version: String
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,16 @@ import SessionSnodeKit
|
||||||
import SessionUtilitiesKit
|
import SessionUtilitiesKit
|
||||||
|
|
||||||
public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
|
public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
|
||||||
|
struct RequestBody: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case data
|
||||||
|
case sendTo = "send_to"
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: String
|
||||||
|
let sendTo: String
|
||||||
|
}
|
||||||
|
|
||||||
public let message: SnodeMessage
|
public let message: SnodeMessage
|
||||||
public var delegate: JobDelegate?
|
public var delegate: JobDelegate?
|
||||||
public var id: String?
|
public var id: String?
|
||||||
|
@ -32,7 +42,8 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC
|
||||||
coder.encode(failureCount, forKey: "failureCount")
|
coder.encode(failureCount, forKey: "failureCount")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Running
|
// MARK: - Running
|
||||||
|
|
||||||
public func execute() {
|
public func execute() {
|
||||||
let _: Promise<Void> = execute()
|
let _: Promise<Void> = execute()
|
||||||
}
|
}
|
||||||
|
@ -42,10 +53,18 @@ public final class NotifyPNServerJob : NSObject, Job, NSCoding { // NSObject/NSC
|
||||||
JobQueue.currentlyExecutingJobs.insert(id)
|
JobQueue.currentlyExecutingJobs.insert(id)
|
||||||
}
|
}
|
||||||
let server = PushNotificationAPI.server
|
let server = PushNotificationAPI.server
|
||||||
let parameters = [ "data" : message.data.description, "send_to" : message.recipient ]
|
|
||||||
let url = URL(string: "\(server)/notify")!
|
let url = URL(string: "\(server)/notify")!
|
||||||
let request = TSRequest(url: url, method: "POST", parameters: parameters)
|
let requestBody: RequestBody = RequestBody(data: message.data.description, sendTo: message.recipient)
|
||||||
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
|
|
||||||
|
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
|
||||||
|
return Promise(error: HTTP.Error.invalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
var request: URLRequest = URLRequest(url: url)
|
||||||
|
request.httpMethod = "POST"
|
||||||
|
request.allHTTPHeaderFields = [ Header.contentType.rawValue: "application/json" ]
|
||||||
|
request.httpBody = body
|
||||||
|
|
||||||
let promise = attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.global()) {
|
let promise = attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.global()) {
|
||||||
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: PushNotificationAPI.serverPublicKey).map { _ in }
|
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: PushNotificationAPI.serverPublicKey).map { _ in }
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct AuthTokenResponse: Codable {
|
||||||
|
struct Challenge: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case ciphertext = "ciphertext"
|
||||||
|
case ephemeralPublicKey = "ephemeral_public_key"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ciphertext: Data
|
||||||
|
let ephemeralPublicKey: Data
|
||||||
|
}
|
||||||
|
|
||||||
|
let challenge: Challenge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Codable
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2.AuthTokenResponse.Challenge {
|
||||||
|
init(from decoder: Decoder) throws {
|
||||||
|
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
let base64EncodedCiphertext: String = try container.decode(String.self, forKey: .ciphertext)
|
||||||
|
let base64EncodedEphemeralPublicKey: String = try container.decode(String.self, forKey: .ephemeralPublicKey)
|
||||||
|
|
||||||
|
guard let ciphertext = Data(base64Encoded: base64EncodedCiphertext), let ephemeralPublicKey = Data(base64Encoded: base64EncodedEphemeralPublicKey) else {
|
||||||
|
throw OpenGroupAPIV2.Error.parsingFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
self = OpenGroupAPIV2.AuthTokenResponse.Challenge(
|
||||||
|
ciphertext: ciphertext,
|
||||||
|
ephemeralPublicKey: ephemeralPublicKey
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container: KeyedEncodingContainer<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
try container.encode(ciphertext.base64EncodedString(), forKey: .ciphertext)
|
||||||
|
try container.encode(ephemeralPublicKey.base64EncodedString(), forKey: .ephemeralPublicKey)
|
||||||
|
}
|
||||||
|
}
|
27
SessionMessagingKit/Open Groups/Models/CompactPollBody.swift
Normal file
27
SessionMessagingKit/Open Groups/Models/CompactPollBody.swift
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct CompactPollBody: Codable {
|
||||||
|
struct Room: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id = "room_id"
|
||||||
|
case fromMessageServerId = "from_message_server_id"
|
||||||
|
case fromDeletionServerId = "from_deletion_server_id"
|
||||||
|
|
||||||
|
// TODO: Remove this legacy value
|
||||||
|
case legacyAuthToken = "auth_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: String
|
||||||
|
let fromMessageServerId: Int64?
|
||||||
|
let fromDeletionServerId: Int64?
|
||||||
|
|
||||||
|
// TODO: This is a legacy value
|
||||||
|
let legacyAuthToken: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
let requests: [Room]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
public struct CompactPollResponse: Codable {
|
||||||
|
public struct Result: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case room = "room_id"
|
||||||
|
case statusCode = "status_code"
|
||||||
|
case messages
|
||||||
|
case deletions
|
||||||
|
case moderators
|
||||||
|
}
|
||||||
|
|
||||||
|
public let room: String
|
||||||
|
public let statusCode: UInt
|
||||||
|
public let messages: [OpenGroupMessageV2]?
|
||||||
|
public let deletions: [Deletion]?
|
||||||
|
public let moderators: [String]?
|
||||||
|
}
|
||||||
|
|
||||||
|
public let results: [Result]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct DeletedMessagesResponse: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case deletions = "ids"
|
||||||
|
}
|
||||||
|
|
||||||
|
let deletions: [Deletion]
|
||||||
|
}
|
||||||
|
}
|
23
SessionMessagingKit/Open Groups/Models/Deletion.swift
Normal file
23
SessionMessagingKit/Open Groups/Models/Deletion.swift
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
public struct Deletion: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case deletedMessageID = "deleted_message_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: Int64
|
||||||
|
let deletedMessageID: Int64
|
||||||
|
|
||||||
|
public static func from(_ json: JSON) -> Deletion? {
|
||||||
|
guard let id = json["id"] as? Int64, let deletedMessageID = json["deleted_message_id"] as? Int64 else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return Deletion(id: id, deletedMessageID: deletedMessageID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct GetInfoResponse: Codable {
|
||||||
|
let room: RoomInfo
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct MemberCountResponse: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case memberCount = "member_count"
|
||||||
|
}
|
||||||
|
|
||||||
|
let memberCount: UInt64
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct ModeratorsResponse: Codable {
|
||||||
|
let moderators: [String]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
import Foundation
|
||||||
|
import SessionUtilitiesKit
|
||||||
|
|
||||||
|
public struct OpenGroupMessageV2: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case serverID = "server_id"
|
||||||
|
case sender = "public_key"
|
||||||
|
case sentTimestamp = "timestamp"
|
||||||
|
case base64EncodedData = "data"
|
||||||
|
case base64EncodedSignature = "signature"
|
||||||
|
}
|
||||||
|
|
||||||
|
public let serverID: Int64?
|
||||||
|
public let sender: String?
|
||||||
|
public let sentTimestamp: UInt64
|
||||||
|
/// The serialized protobuf in base64 encoding.
|
||||||
|
public let base64EncodedData: String
|
||||||
|
/// When sending a message, the sender signs the serialized protobuf with their private key so that
|
||||||
|
/// a receiving user can verify that the message wasn't tampered with.
|
||||||
|
public let base64EncodedSignature: String?
|
||||||
|
|
||||||
|
public func sign(with publicKey: String) -> OpenGroupMessageV2? {
|
||||||
|
// TODO: Swap to use blinded key
|
||||||
|
guard let userKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair() else { return nil }
|
||||||
|
guard let data = Data(base64Encoded: base64EncodedData) else { return nil }
|
||||||
|
guard let signature = try? Ed25519.sign(data, with: userKeyPair) else {
|
||||||
|
SNLog("Failed to sign open group message.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenGroupMessageV2(
|
||||||
|
serverID: serverID,
|
||||||
|
sender: sender,
|
||||||
|
sentTimestamp: sentTimestamp,
|
||||||
|
base64EncodedData: base64EncodedData,
|
||||||
|
base64EncodedSignature: signature.base64EncodedString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Decoder
|
||||||
|
|
||||||
|
extension OpenGroupMessageV2 {
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container: KeyedDecodingContainer<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
let sender: String = try container.decode(String.self, forKey: .sender)
|
||||||
|
let base64EncodedData: String = try container.decode(String.self, forKey: .base64EncodedData)
|
||||||
|
let base64EncodedSignature: String = try container.decode(String.self, forKey: .base64EncodedSignature)
|
||||||
|
|
||||||
|
// Validate the message signature
|
||||||
|
guard let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else {
|
||||||
|
throw OpenGroupAPIV2.Error.parsingFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
let publicKey = Data(hex: sender.removingIdPrefixIfNeeded())
|
||||||
|
let isValid = (try? Ed25519.verifySignature(signature, publicKey: publicKey, data: data)) ?? false
|
||||||
|
|
||||||
|
guard isValid else {
|
||||||
|
SNLog("Ignoring message with invalid signature.")
|
||||||
|
throw OpenGroupAPIV2.Error.parsingFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
self = OpenGroupMessageV2(
|
||||||
|
serverID: try? container.decode(Int64.self, forKey: .serverID),
|
||||||
|
sender: sender,
|
||||||
|
sentTimestamp: try container.decode(UInt64.self, forKey: .sentTimestamp),
|
||||||
|
base64EncodedData: base64EncodedData,
|
||||||
|
base64EncodedSignature: base64EncodedSignature
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import Sodium
|
||||||
|
import SessionUtilitiesKit
|
||||||
|
|
||||||
@objc(SNOpenGroupV2)
|
@objc(SNOpenGroupV2)
|
||||||
public final class OpenGroupV2 : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
|
public final class OpenGroupV2 : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
|
13
SessionMessagingKit/Open Groups/Models/PublicKeyBody.swift
Normal file
13
SessionMessagingKit/Open Groups/Models/PublicKeyBody.swift
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct PublicKeyBody: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case publicKey = "public_key"
|
||||||
|
}
|
||||||
|
|
||||||
|
let publicKey: String
|
||||||
|
}
|
||||||
|
}
|
17
SessionMessagingKit/Open Groups/Models/RoomInfo.swift
Normal file
17
SessionMessagingKit/Open Groups/Models/RoomInfo.swift
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
public struct RoomInfo: Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case id
|
||||||
|
case name
|
||||||
|
case imageID = "image_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
public let id: String
|
||||||
|
public let name: String
|
||||||
|
public let imageID: String?
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct RoomsResponse: Codable {
|
||||||
|
let rooms: [RoomInfo]
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -82,6 +82,7 @@ public final class OpenGroupManagerV2 : NSObject {
|
||||||
|
|
||||||
public func delete(_ openGroup: OpenGroupV2, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) {
|
public func delete(_ openGroup: OpenGroupV2, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) {
|
||||||
let storage = SNMessagingKitConfiguration.shared.storage
|
let storage = SNMessagingKitConfiguration.shared.storage
|
||||||
|
|
||||||
// Stop the poller if needed
|
// Stop the poller if needed
|
||||||
let openGroups = storage.getAllV2OpenGroups().values.filter { $0.server == openGroup.server }
|
let openGroups = storage.getAllV2OpenGroups().values.filter { $0.server == openGroup.server }
|
||||||
if openGroups.count == 1 && openGroups.last == openGroup {
|
if openGroups.count == 1 && openGroups.last == openGroup {
|
||||||
|
@ -89,6 +90,7 @@ public final class OpenGroupManagerV2 : NSObject {
|
||||||
poller?.stop()
|
poller?.stop()
|
||||||
pollers[openGroup.server] = nil
|
pollers[openGroup.server] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all data
|
// Remove all data
|
||||||
var messageIDs: Set<String> = []
|
var messageIDs: Set<String> = []
|
||||||
var messageTimestamps: Set<UInt64> = []
|
var messageTimestamps: Set<UInt64> = []
|
||||||
|
@ -101,10 +103,14 @@ public final class OpenGroupManagerV2 : NSObject {
|
||||||
Storage.shared.removeLastMessageServerID(for: openGroup.room, on: openGroup.server, using: transaction)
|
Storage.shared.removeLastMessageServerID(for: openGroup.room, on: openGroup.server, using: transaction)
|
||||||
Storage.shared.removeLastDeletionServerID(for: openGroup.room, on: openGroup.server, using: transaction)
|
Storage.shared.removeLastDeletionServerID(for: openGroup.room, on: openGroup.server, using: transaction)
|
||||||
let _ = OpenGroupAPIV2.deleteAuthToken(for: openGroup.room, on: openGroup.server)
|
let _ = OpenGroupAPIV2.deleteAuthToken(for: openGroup.room, on: openGroup.server)
|
||||||
Storage.shared.removeOpenGroupPublicKey(for: openGroup.server, using: transaction)
|
|
||||||
thread.removeAllThreadInteractions(with: transaction)
|
thread.removeAllThreadInteractions(with: transaction)
|
||||||
thread.remove(with: transaction)
|
thread.remove(with: transaction)
|
||||||
Storage.shared.removeV2OpenGroup(for: thread.uniqueId!, using: transaction)
|
Storage.shared.removeV2OpenGroup(for: thread.uniqueId!, using: transaction)
|
||||||
|
|
||||||
|
// Only remove the open group public key if the user isn't in any other rooms
|
||||||
|
if openGroups.count <= 1 {
|
||||||
|
Storage.shared.removeOpenGroupPublicKey(for: openGroup.server, using: transaction)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Convenience
|
// MARK: Convenience
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
|
|
||||||
public struct OpenGroupMessageV2 {
|
|
||||||
public let serverID: Int64?
|
|
||||||
public let sender: String?
|
|
||||||
public let sentTimestamp: UInt64
|
|
||||||
/// The serialized protobuf in base64 encoding.
|
|
||||||
public let base64EncodedData: String
|
|
||||||
/// When sending a message, the sender signs the serialized protobuf with their private key so that
|
|
||||||
/// a receiving user can verify that the message wasn't tampered with.
|
|
||||||
public let base64EncodedSignature: String?
|
|
||||||
|
|
||||||
public func sign() -> OpenGroupMessageV2? {
|
|
||||||
let userKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair()!
|
|
||||||
let data = Data(base64Encoded: base64EncodedData)!
|
|
||||||
guard let signature = try? Ed25519.sign(data, with: userKeyPair) else {
|
|
||||||
SNLog("Failed to sign open group message.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return OpenGroupMessageV2(serverID: serverID, sender: sender, sentTimestamp: sentTimestamp,
|
|
||||||
base64EncodedData: base64EncodedData, base64EncodedSignature: signature.base64EncodedString())
|
|
||||||
}
|
|
||||||
|
|
||||||
public func toJSON() -> JSON? {
|
|
||||||
var result: JSON = [ "data" : base64EncodedData, "timestamp" : sentTimestamp ]
|
|
||||||
if let serverID = serverID { result["server_id"] = serverID }
|
|
||||||
if let sender = sender { result["public_key"] = sender }
|
|
||||||
if let base64EncodedSignature = base64EncodedSignature { result["signature"] = base64EncodedSignature }
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func fromJSON(_ json: JSON) -> OpenGroupMessageV2? {
|
|
||||||
guard let base64EncodedData = json["data"] as? String, let sentTimestamp = json["timestamp"] as? UInt64 else { return nil }
|
|
||||||
let serverID = json["server_id"] as? Int64
|
|
||||||
let sender = json["public_key"] as? String
|
|
||||||
let base64EncodedSignature = json["signature"] as? String
|
|
||||||
return OpenGroupMessageV2(serverID: serverID, sender: sender, sentTimestamp: sentTimestamp, base64EncodedData: base64EncodedData, base64EncodedSignature: base64EncodedSignature)
|
|
||||||
}
|
|
||||||
}
|
|
83
SessionMessagingKit/Open Groups/Types/Endpoint.swift
Normal file
83
SessionMessagingKit/Open Groups/Types/Endpoint.swift
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum Endpoint {
|
||||||
|
case files
|
||||||
|
case file(UInt64)
|
||||||
|
|
||||||
|
case messages
|
||||||
|
case messagesForServer(Int64)
|
||||||
|
case deletedMessages
|
||||||
|
|
||||||
|
case moderators
|
||||||
|
|
||||||
|
case blockList
|
||||||
|
case blockListIndividual(String)
|
||||||
|
case banAndDeleteAll
|
||||||
|
|
||||||
|
case rooms
|
||||||
|
case roomInfo(String)
|
||||||
|
case roomImage(String)
|
||||||
|
|
||||||
|
// Legacy endpoints (to be deprecated and removed)
|
||||||
|
case legacyCompactPoll(legacyAuth: Bool)
|
||||||
|
case legacyAuthToken(legacyAuth: Bool)
|
||||||
|
case legacyAuthTokenChallenge(legacyAuth: Bool)
|
||||||
|
case legacyAuthTokenClaim(legacyAuth: Bool)
|
||||||
|
case legacyMemberCount(legacyAuth: Bool)
|
||||||
|
|
||||||
|
var path: String {
|
||||||
|
switch self {
|
||||||
|
case .files: return "files"
|
||||||
|
case .file(let fileId): return "files/\(fileId)"
|
||||||
|
|
||||||
|
case .messages: return "messages"
|
||||||
|
case .messagesForServer(let serverId): return "messages/\(serverId)"
|
||||||
|
case .deletedMessages: return "deleted_messages"
|
||||||
|
|
||||||
|
case .moderators: return "moderators"
|
||||||
|
|
||||||
|
case .blockList: return "block_list"
|
||||||
|
case .blockListIndividual(let publicKey): return "block_list/\(publicKey)"
|
||||||
|
case .banAndDeleteAll: return "ban_and_delete_all"
|
||||||
|
|
||||||
|
case .rooms: return "rooms"
|
||||||
|
case .roomInfo(let roomName): return "rooms/\(roomName)"
|
||||||
|
case .roomImage(let roomName): return "rooms/\(roomName)/image"
|
||||||
|
|
||||||
|
// Legacy endpoints (to be deprecated and removed)
|
||||||
|
// TODO: Look for a nicer way to prepend 'legacy'? (OnionRequestAPI messes with this but the new auth needs it to be correct...)
|
||||||
|
case .legacyCompactPoll(let useLegacyAuth):
|
||||||
|
return "\(useLegacyAuth ? "" : "legacy/")compact_poll"
|
||||||
|
|
||||||
|
case .legacyAuthToken(let useLegacyAuth):
|
||||||
|
return "\(useLegacyAuth ? "" : "legacy/")auth_token"
|
||||||
|
|
||||||
|
case .legacyAuthTokenChallenge(let useLegacyAuth):
|
||||||
|
return "\(useLegacyAuth ? "" : "legacy/")auth_token_challenge"
|
||||||
|
|
||||||
|
case .legacyAuthTokenClaim(let useLegacyAuth):
|
||||||
|
return "\(useLegacyAuth ? "" : "legacy/")claim_auth_token"
|
||||||
|
|
||||||
|
case .legacyMemberCount(let useLegacyAuth):
|
||||||
|
return "\(useLegacyAuth ? "" : "legacy/")member_count"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var useLegacyAuth: Bool {
|
||||||
|
switch self {
|
||||||
|
// File upload/download should use legacy auth
|
||||||
|
case .files, .file: return true
|
||||||
|
|
||||||
|
case .legacyCompactPoll(let useLegacyAuth),
|
||||||
|
.legacyAuthToken(let useLegacyAuth),
|
||||||
|
.legacyAuthTokenChallenge(let useLegacyAuth),
|
||||||
|
.legacyAuthTokenClaim(let useLegacyAuth),
|
||||||
|
.legacyMemberCount(let useLegacyAuth):
|
||||||
|
return useLegacyAuth
|
||||||
|
|
||||||
|
default: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
SessionMessagingKit/Open Groups/Types/Error.swift
Normal file
25
SessionMessagingKit/Open Groups/Types/Error.swift
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
public enum Error: LocalizedError {
|
||||||
|
case generic
|
||||||
|
case parsingFailed
|
||||||
|
case decryptionFailed
|
||||||
|
case signingFailed
|
||||||
|
case invalidURL
|
||||||
|
case noPublicKey
|
||||||
|
|
||||||
|
public var errorDescription: String? {
|
||||||
|
switch self {
|
||||||
|
case .generic: return "An error occurred."
|
||||||
|
case .parsingFailed: return "Invalid response."
|
||||||
|
case .decryptionFailed: return "Couldn't decrypt response."
|
||||||
|
case .signingFailed: return "Couldn't sign message."
|
||||||
|
case .invalidURL: return "Invalid URL."
|
||||||
|
case .noPublicKey: return "Couldn't find server public key."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Sodium
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
class NonceGenerator16Byte: NonceGenerator {
|
||||||
|
var NonceBytes: Int { 16 }
|
||||||
|
}
|
||||||
|
}
|
15
SessionMessagingKit/Open Groups/Types/Personalization.swift
Normal file
15
SessionMessagingKit/Open Groups/Types/Personalization.swift
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Sodium
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
public enum Personalization: String {
|
||||||
|
case sharedKeys = "sogs.shared_keys"
|
||||||
|
case authHeader = "sogs.auth_header"
|
||||||
|
|
||||||
|
var bytes: Bytes {
|
||||||
|
return self.rawValue.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
SessionMessagingKit/Open Groups/Types/Request.swift
Normal file
57
SessionMessagingKit/Open Groups/Types/Request.swift
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension OpenGroupAPIV2 {
|
||||||
|
struct Request {
|
||||||
|
let verb: HTTP.Verb
|
||||||
|
let room: String?
|
||||||
|
let server: String
|
||||||
|
let endpoint: Endpoint
|
||||||
|
let queryParameters: [QueryParam: String]
|
||||||
|
let body: Data?
|
||||||
|
let headers: [Header: String]
|
||||||
|
let isAuthRequired: Bool
|
||||||
|
/// Always `true` under normal circumstances. You might want to disable
|
||||||
|
/// this when running over Lokinet.
|
||||||
|
let useOnionRouting: Bool
|
||||||
|
|
||||||
|
init(
|
||||||
|
verb: HTTP.Verb,
|
||||||
|
room: String?,
|
||||||
|
server: String,
|
||||||
|
endpoint: Endpoint,
|
||||||
|
queryParameters: [QueryParam: String] = [:],
|
||||||
|
body: Data? = nil,
|
||||||
|
headers: [Header: String] = [:],
|
||||||
|
isAuthRequired: Bool = true,
|
||||||
|
useOnionRouting: Bool = true
|
||||||
|
) {
|
||||||
|
self.verb = verb
|
||||||
|
self.room = room
|
||||||
|
self.server = server
|
||||||
|
self.endpoint = endpoint
|
||||||
|
self.queryParameters = queryParameters
|
||||||
|
self.body = body
|
||||||
|
self.headers = headers
|
||||||
|
self.isAuthRequired = isAuthRequired
|
||||||
|
self.useOnionRouting = useOnionRouting
|
||||||
|
}
|
||||||
|
|
||||||
|
var url: URL? {
|
||||||
|
guard verb == .get else { return URL(string: "\(server)/\(endpoint.path)") }
|
||||||
|
|
||||||
|
return URL(
|
||||||
|
string: [
|
||||||
|
"\(server)/\(endpoint.path)",
|
||||||
|
queryParameters
|
||||||
|
.map { key, value in "\(key.rawValue)=\(value)" }
|
||||||
|
.joined(separator: "&")
|
||||||
|
]
|
||||||
|
.compactMap { $0 }
|
||||||
|
.filter { !$0.isEmpty }
|
||||||
|
.joined(separator: "?")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -257,7 +257,8 @@ public final class MessageSender : NSObject {
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Open Groups
|
// MARK: - Open Groups
|
||||||
|
|
||||||
internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise<Void> {
|
internal static func sendToOpenGroupDestination(_ destination: Message.Destination, message: Message, using transaction: Any) -> Promise<Void> {
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
let storage = SNMessagingKitConfiguration.shared.storage
|
let storage = SNMessagingKitConfiguration.shared.storage
|
||||||
|
@ -266,7 +267,15 @@ public final class MessageSender : NSObject {
|
||||||
if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set
|
if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set
|
||||||
message.sentTimestamp = NSDate.millisecondTimestamp()
|
message.sentTimestamp = NSDate.millisecondTimestamp()
|
||||||
}
|
}
|
||||||
message.sender = storage.getUserPublicKey()
|
|
||||||
|
guard let threadId: String = message.threadID, let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadId) else {
|
||||||
|
preconditionFailure()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let userDerivedKey: ECKeyPair = try? OWSIdentityManager.shared().identityKeyPair()?.convert(to: .blinded, with: openGroupV2.publicKey) {
|
||||||
|
message.sender = userDerivedKey.hexEncodedPublicKey
|
||||||
|
}
|
||||||
|
|
||||||
switch destination {
|
switch destination {
|
||||||
case .contact(_): preconditionFailure()
|
case .contact(_): preconditionFailure()
|
||||||
case .closedGroup(_): preconditionFailure()
|
case .closedGroup(_): preconditionFailure()
|
||||||
|
@ -308,9 +317,12 @@ public final class MessageSender : NSObject {
|
||||||
}
|
}
|
||||||
// Send the result
|
// Send the result
|
||||||
guard case .openGroupV2(let room, let server) = destination else { preconditionFailure() }
|
guard case .openGroupV2(let room, let server) = destination else { preconditionFailure() }
|
||||||
|
// TODO: Determine if the 'getV2OpenGroup' call will cause issues
|
||||||
|
guard let threadId: String = message.threadID, let openGroupV2 = Storage.shared.getV2OpenGroup(for: threadId) else { preconditionFailure() }
|
||||||
let openGroupMessage = OpenGroupMessageV2(serverID: nil, sender: nil, sentTimestamp: message.sentTimestamp!,
|
let openGroupMessage = OpenGroupMessageV2(serverID: nil, sender: nil, sentTimestamp: message.sentTimestamp!,
|
||||||
base64EncodedData: plaintext.base64EncodedString(), base64EncodedSignature: nil)
|
base64EncodedData: plaintext.base64EncodedString(), base64EncodedSignature: nil)
|
||||||
OpenGroupAPIV2.send(openGroupMessage, to: room, on: server).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in
|
|
||||||
|
OpenGroupAPIV2.send(openGroupMessage, to: room, on: server, with: openGroupV2.publicKey).done(on: DispatchQueue.global(qos: .userInitiated)) { openGroupMessage in
|
||||||
message.openGroupServerMessageID = given(openGroupMessage.serverID) { UInt64($0) }
|
message.openGroupServerMessageID = given(openGroupMessage.serverID) { UInt64($0) }
|
||||||
storage.write(with: { transaction in
|
storage.write(with: { transaction in
|
||||||
MessageSender.handleSuccessfulMessageSend(message, to: destination, serverTimestamp: openGroupMessage.sentTimestamp, using: transaction)
|
MessageSender.handleSuccessfulMessageSend(message, to: destination, serverTimestamp: openGroupMessage.sentTimestamp, using: transaction)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension PushNotificationAPI {
|
||||||
|
struct RegisterResponse: Codable {
|
||||||
|
let body: String
|
||||||
|
let code: Int
|
||||||
|
let message: String?
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension PushNotificationAPI {
|
||||||
|
struct UnregisterResponse: Codable {
|
||||||
|
let body: String
|
||||||
|
let code: Int
|
||||||
|
let message: String?
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,20 @@ import PromiseKit
|
||||||
|
|
||||||
@objc(LKPushNotificationAPI)
|
@objc(LKPushNotificationAPI)
|
||||||
public final class PushNotificationAPI : NSObject {
|
public final class PushNotificationAPI : NSObject {
|
||||||
|
struct RequestBody: Codable {
|
||||||
|
let token: String
|
||||||
|
let pubKey: String?
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Settings
|
struct ClosedGroupRequestBody: Codable {
|
||||||
|
let token: String
|
||||||
|
let pubKey: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Settings
|
||||||
public static let server = "https://live.apns.getsession.org"
|
public static let server = "https://live.apns.getsession.org"
|
||||||
public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049"
|
public static let serverPublicKey = "642a6585919742e5a2d4dc51244964fbcd8bcab2b75612407de58b810740d049"
|
||||||
|
|
||||||
private static let maxRetryCount: UInt = 4
|
private static let maxRetryCount: UInt = 4
|
||||||
private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60
|
private static let tokenExpirationInterval: TimeInterval = 12 * 60 * 60
|
||||||
|
|
||||||
|
@ -15,29 +25,38 @@ public final class PushNotificationAPI : NSObject {
|
||||||
|
|
||||||
public var endpoint: String {
|
public var endpoint: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .subscribe: return "subscribe_closed_group"
|
case .subscribe: return "subscribe_closed_group"
|
||||||
case .unsubscribe: return "unsubscribe_closed_group"
|
case .unsubscribe: return "unsubscribe_closed_group"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Initialization
|
// MARK: - Initialization
|
||||||
|
|
||||||
private override init() { }
|
private override init() { }
|
||||||
|
|
||||||
// MARK: Registration
|
// MARK: - Registration
|
||||||
|
|
||||||
public static func unregister(_ token: Data) -> Promise<Void> {
|
public static func unregister(_ token: Data) -> Promise<Void> {
|
||||||
let hexEncodedToken = token.toHexString()
|
let requestBody: RequestBody = RequestBody(token: token.toHexString(), pubKey: nil)
|
||||||
let parameters = [ "token" : hexEncodedToken ]
|
|
||||||
|
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
|
||||||
|
return Promise(error: HTTP.Error.invalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
let url = URL(string: "\(server)/unregister")!
|
let url = URL(string: "\(server)/unregister")!
|
||||||
let request = TSRequest(url: url, method: "POST", parameters: parameters)
|
var request: URLRequest = URLRequest(url: url)
|
||||||
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
|
request.httpMethod = "POST"
|
||||||
|
request.allHTTPHeaderFields = [ Header.contentType.rawValue: "application/json" ]
|
||||||
|
request.httpBody = body
|
||||||
|
|
||||||
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
||||||
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
||||||
guard let json = response["body"] as? JSON else {
|
guard let response: UnregisterResponse = try? response.decoded(as: UnregisterResponse.self) else {
|
||||||
return SNLog("Couldn't unregister from push notifications.")
|
return SNLog("Couldn't unregister from push notifications.")
|
||||||
}
|
}
|
||||||
guard json["code"] as? Int != 0 else {
|
guard response.code != 0 else {
|
||||||
return SNLog("Couldn't unregister from push notifications due to error: \(json["message"] as? String ?? "nil").")
|
return SNLog("Couldn't unregister from push notifications due to error: \(response.message ?? "nil").")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +76,13 @@ public final class PushNotificationAPI : NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> Promise<Void> {
|
public static func register(with token: Data, publicKey: String, isForcedUpdate: Bool) -> Promise<Void> {
|
||||||
let hexEncodedToken = token.toHexString()
|
let hexEncodedToken: String = token.toHexString()
|
||||||
|
let requestBody: RequestBody = RequestBody(token: hexEncodedToken, pubKey: publicKey)
|
||||||
|
|
||||||
|
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
|
||||||
|
return Promise(error: HTTP.Error.invalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
let userDefaults = UserDefaults.standard
|
let userDefaults = UserDefaults.standard
|
||||||
let oldToken = userDefaults[.deviceToken]
|
let oldToken = userDefaults[.deviceToken]
|
||||||
let lastUploadTime = userDefaults[.lastDeviceTokenUpload]
|
let lastUploadTime = userDefaults[.lastDeviceTokenUpload]
|
||||||
|
@ -66,18 +91,22 @@ public final class PushNotificationAPI : NSObject {
|
||||||
SNLog("Device token hasn't changed or expired; no need to re-upload.")
|
SNLog("Device token hasn't changed or expired; no need to re-upload.")
|
||||||
return Promise<Void> { $0.fulfill(()) }
|
return Promise<Void> { $0.fulfill(()) }
|
||||||
}
|
}
|
||||||
let parameters = [ "token" : hexEncodedToken, "pubKey" : publicKey ]
|
|
||||||
let url = URL(string: "\(server)/register")!
|
let url = URL(string: "\(server)/register")!
|
||||||
let request = TSRequest(url: url, method: "POST", parameters: parameters)
|
var request: URLRequest = URLRequest(url: url)
|
||||||
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
|
request.httpMethod = "POST"
|
||||||
|
request.allHTTPHeaderFields = [ Header.contentType.rawValue: "application/json" ]
|
||||||
|
request.httpBody = body
|
||||||
|
|
||||||
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
||||||
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
||||||
guard let json = response["body"] as? JSON else {
|
guard let response: RegisterResponse = try? response.decoded(as: RegisterResponse.self) else {
|
||||||
return SNLog("Couldn't register device token.")
|
return SNLog("Couldn't register device token.")
|
||||||
}
|
}
|
||||||
guard json["code"] as? Int != 0 else {
|
guard response.code != 0 else {
|
||||||
return SNLog("Couldn't register device token due to error: \(json["message"] as? String ?? "nil").")
|
return SNLog("Couldn't register device token due to error: \(response.message ?? "nil").")
|
||||||
}
|
}
|
||||||
|
|
||||||
userDefaults[.deviceToken] = hexEncodedToken
|
userDefaults[.deviceToken] = hexEncodedToken
|
||||||
userDefaults[.lastDeviceTokenUpload] = now
|
userDefaults[.lastDeviceTokenUpload] = now
|
||||||
userDefaults[.isUsingFullAPNs] = true
|
userDefaults[.isUsingFullAPNs] = true
|
||||||
|
@ -101,18 +130,26 @@ public final class PushNotificationAPI : NSObject {
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise<Void> {
|
public static func performOperation(_ operation: ClosedGroupOperation, for closedGroupPublicKey: String, publicKey: String) -> Promise<Void> {
|
||||||
let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs]
|
let isUsingFullAPNs = UserDefaults.standard[.isUsingFullAPNs]
|
||||||
|
let requestBody: ClosedGroupRequestBody = ClosedGroupRequestBody(token: closedGroupPublicKey, pubKey: publicKey)
|
||||||
|
|
||||||
guard isUsingFullAPNs else { return Promise<Void> { $0.fulfill(()) } }
|
guard isUsingFullAPNs else { return Promise<Void> { $0.fulfill(()) } }
|
||||||
let parameters = [ "closedGroupPublicKey" : closedGroupPublicKey, "pubKey" : publicKey ]
|
guard let body: Data = try? JSONEncoder().encode(requestBody) else {
|
||||||
|
return Promise(error: HTTP.Error.invalidJSON)
|
||||||
|
}
|
||||||
|
|
||||||
let url = URL(string: "\(server)/\(operation.endpoint)")!
|
let url = URL(string: "\(server)/\(operation.endpoint)")!
|
||||||
let request = TSRequest(url: url, method: "POST", parameters: parameters)
|
var request: URLRequest = URLRequest(url: url)
|
||||||
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
|
request.httpMethod = "POST"
|
||||||
|
request.allHTTPHeaderFields = [ Header.contentType.rawValue: "application/json" ]
|
||||||
|
request.httpBody = body
|
||||||
|
|
||||||
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
let promise: Promise<Void> = attempt(maxRetryCount: maxRetryCount, recoveringOn: DispatchQueue.global()) {
|
||||||
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
OnionRequestAPI.sendOnionRequest(request, to: server, target: "/loki/v2/lsrpc", using: serverPublicKey).map2 { response in
|
||||||
guard let json = response["body"] as? JSON else {
|
guard let response: RegisterResponse = try? response.decoded(as: RegisterResponse.self) else {
|
||||||
return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey).")
|
return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey).")
|
||||||
}
|
}
|
||||||
guard json["code"] as? Int != 0 else {
|
guard response.code != 0 else {
|
||||||
return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(json["message"] as? String ?? "nil").")
|
return SNLog("Couldn't subscribe/unsubscribe for closed group: \(closedGroupPublicKey) due to error: \(response.message ?? "nil").")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,25 +46,32 @@ public final class OpenGroupPollerV2 : NSObject {
|
||||||
self.isPolling = true
|
self.isPolling = true
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
promise.retainUntilComplete()
|
promise.retainUntilComplete()
|
||||||
OpenGroupAPIV2.compactPoll(server).done(on: OpenGroupAPIV2.workQueue) { [weak self] bodies in
|
|
||||||
guard let self = self else { return }
|
// TODO: Update to use the non-legacy version
|
||||||
self.isPolling = false
|
// OpenGroupAPIV2.compactPoll(server)
|
||||||
bodies.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) }
|
OpenGroupAPIV2.legacyCompactPoll(server)
|
||||||
seal.fulfill(())
|
.done(on: OpenGroupAPIV2.workQueue) { [weak self] response in
|
||||||
}.catch(on: OpenGroupAPIV2.workQueue) { error in
|
guard let self = self else { return }
|
||||||
SNLog("Open group polling failed due to error: \(error).")
|
self.isPolling = false
|
||||||
self.isPolling = false
|
response.results.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) }
|
||||||
seal.fulfill(()) // The promise is just used to keep track of when we're done
|
seal.fulfill(())
|
||||||
}
|
}
|
||||||
|
.catch(on: OpenGroupAPIV2.workQueue) { error in
|
||||||
|
SNLog("Open group polling failed due to error: \(error).")
|
||||||
|
self.isPolling = false
|
||||||
|
seal.fulfill(()) // The promise is just used to keep track of when we're done
|
||||||
|
}
|
||||||
|
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleCompactPollBody(_ body: OpenGroupAPIV2.CompactPollResponseBody, isBackgroundPoll: Bool) {
|
private func handleCompactPollBody(_ body: OpenGroupAPIV2.CompactPollResponse.Result, isBackgroundPoll: Bool) {
|
||||||
let storage = SNMessagingKitConfiguration.shared.storage
|
let storage = SNMessagingKitConfiguration.shared.storage
|
||||||
// - Messages
|
// - Messages
|
||||||
// Sorting the messages by server ID before importing them fixes an issue where messages that quote older messages can't find those older messages
|
// Sorting the messages by server ID before importing them fixes an issue where messages that quote older messages can't find those older messages
|
||||||
let openGroupID = "\(server).\(body.room)"
|
let openGroupID = "\(server).\(body.room)"
|
||||||
let messages = body.messages.sorted { $0.serverID! < $1.serverID! } // Safe because messages with a nil serverID are filtered out
|
let messages = (body.messages ?? []).sorted { ($0.serverID ?? 0) < ($1.serverID ?? 0) }
|
||||||
|
|
||||||
storage.write { transaction in
|
storage.write { transaction in
|
||||||
messages.forEach { message in
|
messages.forEach { message in
|
||||||
guard let data = Data(base64Encoded: message.base64EncodedData) else {
|
guard let data = Data(base64Encoded: message.base64EncodedData) else {
|
||||||
|
@ -82,24 +89,29 @@ public final class OpenGroupPollerV2 : NSObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - Moderators
|
// - Moderators
|
||||||
if var x = OpenGroupAPIV2.moderators[server] {
|
if var x = OpenGroupAPIV2.moderators[server] {
|
||||||
x[body.room] = Set(body.moderators)
|
x[body.room] = Set(body.moderators ?? [])
|
||||||
OpenGroupAPIV2.moderators[server] = x
|
OpenGroupAPIV2.moderators[server] = x
|
||||||
} else {
|
|
||||||
OpenGroupAPIV2.moderators[server] = [ body.room : Set(body.moderators) ]
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
OpenGroupAPIV2.moderators[server] = [ body.room : Set(body.moderators ?? []) ]
|
||||||
|
}
|
||||||
|
|
||||||
// - Deletions
|
// - Deletions
|
||||||
let deletedMessageServerIDs = Set(body.deletions.map { UInt64($0.deletedMessageID) })
|
let deletedMessageServerIDs = Set((body.deletions ?? []).map { UInt64($0.deletedMessageID) })
|
||||||
storage.write { transaction in
|
storage.write { transaction in
|
||||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||||
guard let threadID = storage.v2GetThreadID(for: openGroupID),
|
guard let threadID = storage.v2GetThreadID(for: openGroupID),
|
||||||
let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction) else { return }
|
let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction) else { return }
|
||||||
var messagesToRemove: [TSMessage] = []
|
var messagesToRemove: [TSMessage] = []
|
||||||
|
|
||||||
thread.enumerateInteractions(with: transaction) { interaction, stop in
|
thread.enumerateInteractions(with: transaction) { interaction, stop in
|
||||||
guard let message = interaction as? TSMessage, deletedMessageServerIDs.contains(message.openGroupServerMessageID) else { return }
|
guard let message = interaction as? TSMessage, deletedMessageServerIDs.contains(message.openGroupServerMessageID) else { return }
|
||||||
messagesToRemove.append(message)
|
messagesToRemove.append(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
messagesToRemove.forEach { $0.remove(with: transaction) }
|
messagesToRemove.forEach { $0.remove(with: transaction) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
SessionMessagingKit/Utilities/Atomic.swift
Normal file
27
SessionMessagingKit/Utilities/Atomic.swift
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// The `Atomic<T>` wrapper is a generic wrapper providing a thread-safe way to get and set a value
|
||||||
|
@propertyWrapper
|
||||||
|
struct Atomic<Value> {
|
||||||
|
private let lock = DispatchSemaphore(value: 1)
|
||||||
|
private var value: Value
|
||||||
|
|
||||||
|
init(_ initialValue: Value) {
|
||||||
|
self.value = initialValue
|
||||||
|
}
|
||||||
|
|
||||||
|
var wrappedValue: Value {
|
||||||
|
get {
|
||||||
|
lock.wait()
|
||||||
|
defer { lock.signal() }
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
lock.wait()
|
||||||
|
value = newValue
|
||||||
|
lock.signal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
SessionMessagingKit/Utilities/ECKeyPair+Conversion.swift
Normal file
34
SessionMessagingKit/Utilities/ECKeyPair+Conversion.swift
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Curve25519Kit
|
||||||
|
import SessionUtilitiesKit
|
||||||
|
import Sodium
|
||||||
|
|
||||||
|
public extension ECKeyPair {
|
||||||
|
func convert(to targetPrefix: IdPrefix, with otherKey: String, using sodium: Sodium = Sodium()) throws -> ECKeyPair? {
|
||||||
|
guard let publicKeyPrefix: IdPrefix = IdPrefix(with: hexEncodedPublicKey) else { return nil }
|
||||||
|
|
||||||
|
switch (publicKeyPrefix, targetPrefix) {
|
||||||
|
case (.standard, .blinded): // Only support standard -> blinded conversions
|
||||||
|
// TODO: Figure out why this is broken...
|
||||||
|
// guard let otherPubKeyData: Data = otherKey.data(using: .utf8) else { return nil }
|
||||||
|
guard let otherPubKeyData: Data = otherKey.dataFromHex() else { return nil }
|
||||||
|
guard let otherPubKeyHashBytes: Bytes = sodium.genericHash.hash(message: [UInt8](otherPubKeyData)) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard let blindedPublicKey: Sodium.SharedSecret = sodium.sharedSecret(otherPubKeyHashBytes, [UInt8](publicKey)) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard let blindedPrivateKey: Sodium.SharedSecret = sodium.sharedSecret(otherPubKeyHashBytes, [UInt8](privateKey)) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return try BlindedECKeyPair(publicKeyData: blindedPublicKey, privateKeyData: blindedPrivateKey)
|
||||||
|
|
||||||
|
case (.standard, .standard): return self
|
||||||
|
case (.blinded, .blinded): return self
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,22 +41,27 @@ extension Sign {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Sodium {
|
extension Sodium {
|
||||||
public typealias SOGSDerivedKey = Data
|
public typealias SharedSecret = Data
|
||||||
|
|
||||||
private static let publicKeyBytes: Int = Int(crypto_scalarmult_bytes())
|
private static let publicKeyBytes: Int = Int(crypto_scalarmult_bytes())
|
||||||
private static let sharedSecretBytes: Int = Int(crypto_scalarmult_bytes())
|
private static let sharedSecretBytes: Int = Int(crypto_scalarmult_bytes())
|
||||||
|
|
||||||
public func derivedKey(serverPublicKeyBytes: [UInt8], userKeyBytes: [UInt8]) -> SOGSDerivedKey? {
|
public func sharedSecret(_ firstKeyBytes: [UInt8], _ secondKeyBytes: [UInt8]) -> SharedSecret? {
|
||||||
guard serverPublicKeyBytes.count == Sodium.publicKeyBytes && userKeyBytes.count == Sodium.publicKeyBytes else { return nil }
|
guard firstKeyBytes.count == Sodium.publicKeyBytes && secondKeyBytes.count == Sodium.publicKeyBytes else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
let sharedSecretPtr: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: Sodium.sharedSecretBytes)
|
let sharedSecretPtr: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: Sodium.sharedSecretBytes)
|
||||||
let result = userKeyBytes.withUnsafeBytes { (userPublicKeyPtr: UnsafeRawBufferPointer) in
|
let result = secondKeyBytes.withUnsafeBytes { (secondKeyPtr: UnsafeRawBufferPointer) -> Int32 in
|
||||||
return serverPublicKeyBytes.withUnsafeBytes { (serverPublicKeyPtr: UnsafeRawBufferPointer) -> Int32 in
|
return firstKeyBytes.withUnsafeBytes { (firstKeyPtr: UnsafeRawBufferPointer) -> Int32 in
|
||||||
guard let serverKeyBaseAddress: UnsafePointer<UInt8> = serverPublicKeyPtr.baseAddress?.assumingMemoryBound(to: UInt8.self), let userKeyBaseAddress: UnsafePointer<UInt8> = userPublicKeyPtr.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
guard let firstKeyBaseAddress: UnsafePointer<UInt8> = firstKeyPtr.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
guard let secondKeyBaseAddress: UnsafePointer<UInt8> = secondKeyPtr.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
return crypto_scalarmult(sharedSecretPtr, serverKeyBaseAddress, userKeyBaseAddress)
|
return crypto_scalarmult(sharedSecretPtr, firstKeyBaseAddress, secondKeyBaseAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,3 +70,30 @@ extension Sodium {
|
||||||
return Data(bytes: sharedSecretPtr, count: Sodium.sharedSecretBytes)
|
return Data(bytes: sharedSecretPtr, count: Sodium.sharedSecretBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension GenericHash {
|
||||||
|
public func hashSaltPersonal(
|
||||||
|
message: Bytes,
|
||||||
|
outputLength: Int,
|
||||||
|
key: Bytes? = nil,
|
||||||
|
salt: Bytes,
|
||||||
|
personal: Bytes
|
||||||
|
) -> Bytes? {
|
||||||
|
var output: [UInt8] = [UInt8](repeating: 0, count: outputLength)
|
||||||
|
|
||||||
|
let result = crypto_generichash_blake2b_salt_personal(
|
||||||
|
&output,
|
||||||
|
outputLength,
|
||||||
|
message,
|
||||||
|
UInt64(message.count),
|
||||||
|
key,
|
||||||
|
(key?.count ?? 0),
|
||||||
|
salt,
|
||||||
|
personal
|
||||||
|
)
|
||||||
|
|
||||||
|
guard result == 0 else { return nil }
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Foundation
|
||||||
import CryptoSwift
|
import CryptoSwift
|
||||||
import PromiseKit
|
import PromiseKit
|
||||||
import SessionUtilitiesKit
|
import SessionUtilitiesKit
|
||||||
|
@ -301,54 +302,54 @@ public enum OnionRequestAPI {
|
||||||
|
|
||||||
// MARK: Public API
|
// MARK: Public API
|
||||||
/// Sends an onion request to `snode`. Builds new paths as needed.
|
/// Sends an onion request to `snode`. Builds new paths as needed.
|
||||||
public static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String? = nil) -> Promise<JSON> {
|
public static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String? = nil) -> Promise<Data> {
|
||||||
let payload: JSON = [ "method" : method.rawValue, "params" : parameters ]
|
let payload: JSON = [ "method" : method.rawValue, "params" : parameters ]
|
||||||
return sendOnionRequest(with: payload, to: Destination.snode(snode)).recover2 { error -> Promise<JSON> in
|
return sendOnionRequest(with: payload, to: Destination.snode(snode)).recover2 { error -> Promise<Data> in
|
||||||
guard case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, let json, _) = error else { throw error }
|
guard case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, let json, _) = error else { throw error }
|
||||||
throw SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode, associatedWith: publicKey) ?? error
|
throw SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode, associatedWith: publicKey) ?? error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends an onion request to `server`. Builds new paths as needed.
|
/// Sends an onion request to `server`. Builds new paths as needed.
|
||||||
public static func sendOnionRequest(_ request: NSURLRequest, to server: String, target: String = "/loki/v3/lsrpc", using x25519PublicKey: String) -> Promise<JSON> {
|
public static func sendOnionRequest(_ request: URLRequest, to server: String, target: String = "/loki/v3/lsrpc", using x25519PublicKey: String) -> Promise<Data> {
|
||||||
var rawHeaders = request.allHTTPHeaderFields ?? [:]
|
|
||||||
rawHeaders.removeValue(forKey: "User-Agent")
|
|
||||||
var headers: JSON = rawHeaders.mapValues { value in
|
|
||||||
switch value.lowercased() {
|
|
||||||
case "true": return true
|
|
||||||
case "false": return false
|
|
||||||
default: return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
guard let url = request.url, let host = request.url?.host else { return Promise(error: Error.invalidURL) }
|
guard let url = request.url, let host = request.url?.host else { return Promise(error: Error.invalidURL) }
|
||||||
var endpoint = url.path.removingPrefix("/")
|
|
||||||
if let query = url.query { endpoint += "?\(query)" }
|
var headers: JSON = (request.allHTTPHeaderFields ?? [:])
|
||||||
let scheme = url.scheme
|
.mapValues { value -> Any in
|
||||||
let port = given(url.port) { UInt16($0) }
|
switch value.lowercased() {
|
||||||
let parametersAsString: String
|
case "true": return true
|
||||||
if let tsRequest = request as? TSRequest {
|
case "false": return false
|
||||||
headers["Content-Type"] = "application/json"
|
default: return value
|
||||||
let tsRequestParameters = tsRequest.parameters
|
|
||||||
if !tsRequestParameters.isEmpty {
|
|
||||||
guard let parameters = try? JSONSerialization.data(withJSONObject: tsRequestParameters, options: [ .fragmentsAllowed ]) else {
|
|
||||||
return Promise(error: HTTP.Error.invalidJSON)
|
|
||||||
}
|
}
|
||||||
parametersAsString = String(bytes: parameters, encoding: .utf8) ?? "null"
|
|
||||||
} else {
|
|
||||||
parametersAsString = "null"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
headers["Content-Type"] = request.allHTTPHeaderFields!["Content-Type"]
|
|
||||||
if let parametersAsInputStream = request.httpBodyStream, let parameters = try? Data(from: parametersAsInputStream) {
|
|
||||||
parametersAsString = "{ \"fileUpload\" : \"\(String(data: parameters.base64EncodedData(), encoding: .utf8) ?? "null")\" }"
|
|
||||||
} else {
|
|
||||||
parametersAsString = "null"
|
|
||||||
}
|
}
|
||||||
|
.removingValue(forKey: "User-Agent")
|
||||||
|
|
||||||
|
// Note: We need to remove the leading forward slash unless we are explicitly hitting a legacy
|
||||||
|
// endpoint (in which case we need it to ensure the request signing works correctly
|
||||||
|
// TODO: Confirm the 'removingPrefix' isn't going to break the request signing on non-legacy endpoints
|
||||||
|
let endpoint: String = url.path
|
||||||
|
.removingPrefix("/", if: !url.path.starts(with: "/legacy"))
|
||||||
|
.appending(url.query.map { value in "?\(value)" })
|
||||||
|
let scheme: String? = url.scheme
|
||||||
|
let port: UInt16? = url.port.map { UInt16($0) }
|
||||||
|
let bodyAsString: String
|
||||||
|
|
||||||
|
if let body: Data = request.httpBody {
|
||||||
|
headers["Content-Type"] = "application/json" // Assume data is JSON
|
||||||
|
bodyAsString = (String(data: body, encoding: .utf8) ?? "null")
|
||||||
}
|
}
|
||||||
|
else if let inputStream: InputStream = request.httpBodyStream, let body: Data = try? Data(from: inputStream) {
|
||||||
|
headers["Content-Type"] = request.allHTTPHeaderFields!["Content-Type"]
|
||||||
|
bodyAsString = "{ \"fileUpload\" : \"\(String(data: body.base64EncodedData(), encoding: .utf8) ?? "null")\" }"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bodyAsString = "null"
|
||||||
|
}
|
||||||
|
|
||||||
let payload: JSON = [
|
let payload: JSON = [
|
||||||
"body" : parametersAsString,
|
"body" : bodyAsString,
|
||||||
"endpoint" : endpoint,
|
"endpoint" : endpoint,
|
||||||
"method" : request.httpMethod!,
|
"method" : (request.httpMethod ?? "GET"), // Default (if nil) is 'GET'
|
||||||
"headers" : headers
|
"headers" : headers
|
||||||
]
|
]
|
||||||
let destination = Destination.server(host: host, target: target, x25519PublicKey: x25519PublicKey, scheme: scheme, port: port)
|
let destination = Destination.server(host: host, target: target, x25519PublicKey: x25519PublicKey, scheme: scheme, port: port)
|
||||||
|
@ -359,8 +360,8 @@ public enum OnionRequestAPI {
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func sendOnionRequest(with payload: JSON, to destination: Destination) -> Promise<JSON> {
|
public static func sendOnionRequest(with payload: JSON, to destination: Destination) -> Promise<Data> {
|
||||||
let (promise, seal) = Promise<JSON>.pending()
|
let (promise, seal) = Promise<Data>.pending()
|
||||||
var guardSnode: Snode?
|
var guardSnode: Snode?
|
||||||
Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths`
|
Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths`
|
||||||
buildOnion(around: payload, targetedAt: destination).done2 { intermediate in
|
buildOnion(around: payload, targetedAt: destination).done2 { intermediate in
|
||||||
|
@ -401,12 +402,12 @@ public enum OnionRequestAPI {
|
||||||
guard 200...299 ~= statusCode else {
|
guard 200...299 ~= statusCode else {
|
||||||
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: body, destination: destination))
|
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: body, destination: destination))
|
||||||
}
|
}
|
||||||
seal.fulfill(body)
|
seal.fulfill(data)
|
||||||
} else {
|
} else {
|
||||||
guard 200...299 ~= statusCode else {
|
guard 200...299 ~= statusCode else {
|
||||||
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: json, destination: destination))
|
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: json, destination: destination))
|
||||||
}
|
}
|
||||||
seal.fulfill(json)
|
seal.fulfill(data)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
seal.reject(error)
|
seal.reject(error)
|
||||||
|
|
|
@ -2,8 +2,18 @@ import Foundation
|
||||||
|
|
||||||
internal extension String {
|
internal extension String {
|
||||||
|
|
||||||
func removingPrefix(_ prefix: String) -> String {
|
func removingPrefix(_ prefix: String, if condition: Bool = true) -> String {
|
||||||
|
guard condition else { return self }
|
||||||
guard let range = self.range(of: prefix), range.lowerBound == startIndex else { return self }
|
guard let range = self.range(of: prefix), range.lowerBound == startIndex else { return self }
|
||||||
|
|
||||||
return String(self[range.upperBound..<endIndex])
|
return String(self[range.upperBound..<endIndex])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal extension String {
|
||||||
|
func appending(_ other: String?) -> String {
|
||||||
|
guard let value: String = other else { return self }
|
||||||
|
|
||||||
|
return self.appending(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,9 @@ public extension ECKeyPair {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension BlindedECKeyPair {
|
||||||
|
@objc override var hexEncodedPublicKey: String {
|
||||||
|
return IdPrefix.blinded.rawValue + publicKey.map { String(format: "%02hhx", $0) }.joined()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
public extension Array where Element : CustomStringConvertible {
|
|
||||||
|
|
||||||
var prettifiedDescription: String {
|
|
||||||
return "[ " + map { $0.description }.joined(separator: ", ") + " ]"
|
|
||||||
}
|
|
||||||
}
|
|
23
SessionUtilitiesKit/General/Array+Utilities.swift
Normal file
23
SessionUtilitiesKit/General/Array+Utilities.swift
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
public extension Array where Element : CustomStringConvertible {
|
||||||
|
|
||||||
|
var prettifiedDescription: String {
|
||||||
|
return "[ " + map { $0.description }.joined(separator: ", ") + " ]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension Array {
|
||||||
|
func appending(_ other: Element) -> [Element] {
|
||||||
|
var updatedArray: [Element] = self
|
||||||
|
updatedArray.append(other)
|
||||||
|
|
||||||
|
return updatedArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func appending(_ other: [Element]) -> [Element] {
|
||||||
|
var updatedArray: [Element] = self
|
||||||
|
updatedArray.append(contentsOf: other)
|
||||||
|
|
||||||
|
return updatedArray
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
|
|
||||||
public extension Data {
|
|
||||||
|
|
||||||
func removingIdPrefixIfNeeded() -> Data {
|
|
||||||
var result = self
|
|
||||||
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public extension NSData {
|
|
||||||
|
|
||||||
@objc func removingIdPrefixIfNeeded() -> NSData {
|
|
||||||
var result = self as Data
|
|
||||||
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
|
|
||||||
return result as NSData
|
|
||||||
}
|
|
||||||
}
|
|
48
SessionUtilitiesKit/General/Data+Utilities.swift
Normal file
48
SessionUtilitiesKit/General/Data+Utilities.swift
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public extension Data {
|
||||||
|
|
||||||
|
func removingIdPrefixIfNeeded() -> Data {
|
||||||
|
var result = self
|
||||||
|
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func appending(_ other: Data) -> Data {
|
||||||
|
var mutableData: Data = Data()
|
||||||
|
mutableData.append(self)
|
||||||
|
mutableData.append(other)
|
||||||
|
|
||||||
|
return mutableData
|
||||||
|
}
|
||||||
|
|
||||||
|
func appending(_ other: [UInt8]) -> Data {
|
||||||
|
var mutableData: Data = Data()
|
||||||
|
mutableData.append(self)
|
||||||
|
mutableData.append(contentsOf: other)
|
||||||
|
|
||||||
|
return mutableData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public extension NSData {
|
||||||
|
|
||||||
|
@objc func removingIdPrefixIfNeeded() -> NSData {
|
||||||
|
var result = self as Data
|
||||||
|
if result.count == 33 && IdPrefix(with: result.toHexString()) != nil { result.removeFirst() }
|
||||||
|
return result as NSData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Decoding
|
||||||
|
|
||||||
|
public extension Data {
|
||||||
|
func decoded<T: Decodable>(as type: T.Type, customError: Error? = nil) throws -> T {
|
||||||
|
do {
|
||||||
|
return try JSONDecoder().decode(type, from: self)
|
||||||
|
}
|
||||||
|
catch let error {
|
||||||
|
throw (customError ?? error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
|
|
||||||
public extension Dictionary {
|
|
||||||
|
|
||||||
var prettifiedDescription: String {
|
|
||||||
return "[ " + map { key, value in
|
|
||||||
let keyDescription = String(describing: key)
|
|
||||||
let valueDescription = String(describing: value)
|
|
||||||
let maxLength = 20
|
|
||||||
let truncatedValueDescription = valueDescription.count > maxLength ? valueDescription.prefix(maxLength) + "..." : valueDescription
|
|
||||||
return keyDescription + " : " + truncatedValueDescription
|
|
||||||
}.joined(separator: ", ") + " ]"
|
|
||||||
}
|
|
||||||
}
|
|
42
SessionUtilitiesKit/General/Dictionary+Utilities.swift
Normal file
42
SessionUtilitiesKit/General/Dictionary+Utilities.swift
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
public extension Dictionary {
|
||||||
|
|
||||||
|
var prettifiedDescription: String {
|
||||||
|
return "[ " + map { key, value in
|
||||||
|
let keyDescription = String(describing: key)
|
||||||
|
let valueDescription = String(describing: value)
|
||||||
|
let maxLength = 20
|
||||||
|
let truncatedValueDescription = valueDescription.count > maxLength ? valueDescription.prefix(maxLength) + "..." : valueDescription
|
||||||
|
return keyDescription + " : " + truncatedValueDescription
|
||||||
|
}.joined(separator: ", ") + " ]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Functional Convenience
|
||||||
|
|
||||||
|
public extension Dictionary {
|
||||||
|
func setting(_ key: Key, _ value: Value?) -> [Key: Value] {
|
||||||
|
var updatedDictionary: [Key: Value] = self
|
||||||
|
updatedDictionary[key] = value
|
||||||
|
|
||||||
|
return updatedDictionary
|
||||||
|
}
|
||||||
|
|
||||||
|
func updated(with other: [Key: Value]) -> [Key: Value] {
|
||||||
|
var updatedDictionary: [Key: Value] = self
|
||||||
|
|
||||||
|
other.forEach { key, value in
|
||||||
|
updatedDictionary[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedDictionary
|
||||||
|
}
|
||||||
|
|
||||||
|
func removingValue(forKey key: Key) -> [Key: Value] {
|
||||||
|
var updatedDictionary: [Key: Value] = self
|
||||||
|
updatedDictionary.removeValue(forKey: key)
|
||||||
|
|
||||||
|
return updatedDictionary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Curve25519Kit
|
||||||
|
|
||||||
|
/// The `BlindedECKeyPair` is essentially the same as the `ECKeyPair` except it allows us to more easily distinguish between the two,
|
||||||
|
/// additionally when generating the `hexEncodedPublicKey` value it will apply the correct prefix
|
||||||
|
public class BlindedECKeyPair: ECKeyPair {}
|
||||||
|
|
||||||
public enum IdPrefix: String, CaseIterable {
|
public enum IdPrefix: String, CaseIterable {
|
||||||
case standard = "05" // Used for identified users, open groups, etc.
|
case standard = "05" // Used for identified users, open groups, etc.
|
||||||
case blinded = "15" // Used for participants in open groups
|
case blinded = "15" // Used for participants in open groups
|
||||||
|
|
||||||
|
public init?(with sessionId: String) {
|
||||||
|
guard ECKeyPair.isValidHexEncodedPublicKey(candidate: sessionId) else { return nil }
|
||||||
|
guard let targetPrefix: IdPrefix = IdPrefix(rawValue: String(sessionId.prefix(2))) else { return nil }
|
||||||
|
|
||||||
|
self = targetPrefix
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
18
SessionUtilitiesKit/General/String+Encoding.swift
Normal file
18
SessionUtilitiesKit/General/String+Encoding.swift
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
public func dataFromHex() -> Data? {
|
||||||
|
guard (self.count % 2) == 0 else { return nil }
|
||||||
|
|
||||||
|
let chars = self.map { $0 }
|
||||||
|
let bytes: [UInt8] = stride(from: 0, to: chars.count, by: 2)
|
||||||
|
.map { index -> String in String(chars[index]) + String(chars[index + 1]) }
|
||||||
|
.compactMap { (str: String) -> UInt8? in UInt8(str, radix: 16) }
|
||||||
|
|
||||||
|
guard (self.count / bytes.count) == 2 else { return nil }
|
||||||
|
|
||||||
|
return Data(bytes)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,6 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[];
|
||||||
#import <SessionUtilitiesKit/NSUserDefaults+OWS.h>
|
#import <SessionUtilitiesKit/NSUserDefaults+OWS.h>
|
||||||
#import <SessionUtilitiesKit/OWSFileSystem.h>
|
#import <SessionUtilitiesKit/OWSFileSystem.h>
|
||||||
#import <SessionUtilitiesKit/OWSMath.h>
|
#import <SessionUtilitiesKit/OWSMath.h>
|
||||||
#import <SessionUtilitiesKit/TSRequest.h>
|
|
||||||
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
|
#import <SessionUtilitiesKit/TSYapDatabaseObject.h>
|
||||||
#import <SessionUtilitiesKit/UIImage+OWS.h>
|
#import <SessionUtilitiesKit/UIImage+OWS.h>
|
||||||
#import <SessionUtilitiesKit/UIView+OWS.h>
|
#import <SessionUtilitiesKit/UIView+OWS.h>
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
#define textSecureHTTPTimeOut 10
|
|
||||||
|
|
||||||
@interface TSRequest : NSMutableURLRequest
|
|
||||||
|
|
||||||
@property (nonatomic, readonly) NSDictionary<NSString *, id> *parameters;
|
|
||||||
|
|
||||||
- (instancetype)init NS_UNAVAILABLE;
|
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)URL;
|
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)URL
|
|
||||||
cachePolicy:(NSURLRequestCachePolicy)cachePolicy
|
|
||||||
timeoutInterval:(NSTimeInterval)timeoutInterval NS_UNAVAILABLE;
|
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)URL
|
|
||||||
method:(NSString *)method
|
|
||||||
parameters:(nullable NSDictionary<NSString *, id> *)parameters;
|
|
||||||
|
|
||||||
+ (instancetype)requestWithUrl:(NSURL *)url
|
|
||||||
method:(NSString *)method
|
|
||||||
parameters:(nullable NSDictionary<NSString *, id> *)parameters;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
|
@ -1,64 +0,0 @@
|
||||||
#import "TSRequest.h"
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
|
||||||
|
|
||||||
@implementation TSRequest
|
|
||||||
|
|
||||||
- (id)initWithURL:(NSURL *)URL {
|
|
||||||
self = [super initWithURL:URL
|
|
||||||
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
|
|
||||||
timeoutInterval:textSecureHTTPTimeOut];
|
|
||||||
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
_parameters = @{};
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)init
|
|
||||||
{
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wobjc-designated-initializers"
|
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)URL
|
|
||||||
cachePolicy:(NSURLRequestCachePolicy)cachePolicy
|
|
||||||
timeoutInterval:(NSTimeInterval)timeoutInterval
|
|
||||||
{
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithURL:(NSURL *)URL
|
|
||||||
method:(NSString *)method
|
|
||||||
parameters:(nullable NSDictionary<NSString *, id> *)parameters
|
|
||||||
{
|
|
||||||
self = [super initWithURL:URL
|
|
||||||
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
|
|
||||||
timeoutInterval:textSecureHTTPTimeOut];
|
|
||||||
|
|
||||||
if (!self) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
_parameters = parameters ?: @{};
|
|
||||||
|
|
||||||
[self setHTTPMethod:method];
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (instancetype)requestWithUrl:(NSURL *)url
|
|
||||||
method:(NSString *)method
|
|
||||||
parameters:(nullable NSDictionary<NSString *, id> *)parameters
|
|
||||||
{
|
|
||||||
return [[TSRequest alloc] initWithURL:url method:method parameters:parameters];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
|
|
@ -45,7 +45,20 @@ extension MessageSender {
|
||||||
let storage = SNMessagingKitConfiguration.shared.storage
|
let storage = SNMessagingKitConfiguration.shared.storage
|
||||||
if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {
|
if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
AttachmentUploadJob.upload(stream, using: { data in return OpenGroupAPIV2.upload(data, to: v2OpenGroup.room, on: v2OpenGroup.server) }, encrypt: false, onSuccess: { seal.fulfill(()) }, onFailure: { seal.reject($0) })
|
AttachmentUploadJob.upload(
|
||||||
|
stream,
|
||||||
|
using: { data in
|
||||||
|
OpenGroupAPIV2.upload(
|
||||||
|
data,
|
||||||
|
to: v2OpenGroup.room,
|
||||||
|
on: v2OpenGroup.server
|
||||||
|
)
|
||||||
|
},
|
||||||
|
encrypt: false,
|
||||||
|
onSuccess: { seal.fulfill(()) },
|
||||||
|
onFailure: { seal.reject($0) }
|
||||||
|
)
|
||||||
|
|
||||||
return promise
|
return promise
|
||||||
} else {
|
} else {
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
|
@ -78,7 +91,19 @@ extension MessageSender {
|
||||||
let storage = SNMessagingKitConfiguration.shared.storage
|
let storage = SNMessagingKitConfiguration.shared.storage
|
||||||
if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {
|
if let v2OpenGroup = storage.getV2OpenGroup(for: thread.uniqueId!) {
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
AttachmentUploadJob.upload(stream, using: { data in return OpenGroupAPIV2.upload(data, to: v2OpenGroup.room, on: v2OpenGroup.server) }, encrypt: false, onSuccess: { seal.fulfill(()) }, onFailure: { seal.reject($0) })
|
AttachmentUploadJob.upload(
|
||||||
|
stream,
|
||||||
|
using: { data in
|
||||||
|
OpenGroupAPIV2.upload(
|
||||||
|
data,
|
||||||
|
to: v2OpenGroup.room,
|
||||||
|
on: v2OpenGroup.server
|
||||||
|
)
|
||||||
|
},
|
||||||
|
encrypt: false,
|
||||||
|
onSuccess: { seal.fulfill(()) },
|
||||||
|
onFailure: { seal.reject($0) }
|
||||||
|
)
|
||||||
return promise
|
return promise
|
||||||
} else {
|
} else {
|
||||||
let (promise, seal) = Promise<Void>.pending()
|
let (promise, seal) = Promise<Void>.pending()
|
||||||
|
|
Loading…
Reference in a new issue